原子操作CAS与锁实现

(36条消息) 原子操作CAS与锁实现_going with the wind的博客-CSDN博客

 

锁和原子操作

(36条消息) 原子操作CAS与锁实现_摸鱼呀的博客-CSDN博客

 

 

CPU亲缘性

 1 #include <stdio.h>
 2 #include <unistd.h>
 3 #include <sched.h>
 4 
 5 #include <sys/syscall.h>
 6 
 7 
 8 // nginx.conf --> set affinity 0000 0000
 9 void process_affinity(int num) {
10 
11     
12     pid_t self_id = syscall(__NR_gettid);
13 
14     //fd_set
15     cpu_set_t mask;
16     CPU_ZERO(&mask);
17     CPU_SET(self_id % num, &mask);
18 
19     sched_setaffinity(self_id, sizeof(mask), &mask);
20     
21     while(1) usleep(1);
22 }
23 
24 
25 int main() {
26 
27     int num = sysconf(_SC_NPROCESSORS_CONF);
28 
29     printf("num: %d\n", num);
30 #if 0
31 
32     int i = 0;
33     pid_t pid = 0;
34     
35     for (i = 0;i < num/2;i ++) {
36 
37         pid = fork();
38         if (pid <= 0) {
39             break;
40         }
41 
42     }
43 
44     if (pid == 0) {
45         process_affinity(num);
46     }
47 
48 #else
49 
50     int i = 0;
51     
52     for (i = 0;i < num/2;i ++) {
53             
54         pthread_create();
55             
56     }
57 
58 #endif
59     printf("affinity.c: %d\n", pid);
60 
61     while(1) usleep(1);
62 
63 }

 

 

 

 

 

 

大文件如何快速的读进内存里面?

答:使用mmap,把文件映射(DMA,cpu不参与,零拷贝)到内存中来,然后使用多线程操作映射出来的内存。

 

⽂件内存映射mmap解决⼤⽂件快速读写问题

mmap函数主要⽤途有三个:

1、将⼀个普通⽂件映射到内存中,通常在需要对⽂件进⾏频繁读写时使⽤,这样⽤内存读写取代I/O读写,以获得较⾼的性能;

2、将特殊⽂件进⾏匿名内存映射,可以为关联进程提供共享内存空间;

3、为⽆关联的进程提供共享内存空间,⼀般也是将⼀个普通⽂件映射到内存中。

Linux提供了内存映射函数mmap, 它把⽂件内容映射到⼀段内存上(准确说是虚拟内存上), 通过对这段内存的读取和修改, 实现对⽂件的读取和修改。

⼀、使⽤步骤

* ⽤open系统调⽤打开⽂件, 并返回描述符fd.

* ⽤mmap建⽴内存映射, 并返回映射⾸地址指针start.

* 对映射(⽂件)进⾏各种操作, 显⽰(printf), 修改(sprintf).

* ⽤munmap(void *start, size_t lenght)关闭内存映射.

* ⽤close系统调⽤关闭⽂件fd.

⼆、mmap函数⽤法

* 头⽂件:

#include <unistd.h>

#include <sys/mman.h>

* 函数:void *mmap(void *start,size_t length,int prot,int flags,int fd,off_t offsize);

参数start:指向欲映射的内存起始地址,通常设为 NULL,代表让系统⾃动选定地址,映射成功后返回该地址。

参数length:代表将⽂件中多⼤的部分映射到内存。

参数prot:映射区域的保护⽅式。可以为以下⼏种⽅式的组合:

PROT_EXEC 映射区域可被执⾏

PROT_READ 映射区域可被读取

PROT_WRITE 映射区域可被写⼊

PROT_NONE 映射区域不能存取

参数flags:影响映射区域的各种特性。在调⽤mmap()时必须要指定MAP_SHARED 或MAP_PRIVATE。

MAP_FIXED 如果参数start所指的地址⽆法成功建⽴映射时,则放弃映射,不对地址做修正。通常不⿎励⽤此旗标。

MAP_SHARED对映射区域的写⼊数据会复制回⽂件内,⽽且允许其他映射该⽂件的进程共享。

MAP_PRIVATE 对映射区域的写⼊操作会产⽣⼀个映射⽂件的复制,即私⼈的“写⼊时复制”(copy on write)对此区域作的任何修改都不会写回原来的⽂件内容。

MAP_ANONYMOUS建⽴匿名映射。此时会忽略参数fd,不涉及⽂件,⽽且映射区域⽆法和其他进程共享。

MAP_DENYWRITE只允许对映射区域的写⼊操作,其他对⽂件直接写⼊的操作将会被拒绝。

MAP_LOCKED 将映射区域锁定住,这表⽰该区域不会被置换(swap)。

参数fd:要映射到内存中的⽂件描述符。如果使⽤匿名内存映射时,即flags中设置了MAP_ANONYMOUS,fd设为-1。有些系统不⽀持匿名内存映射,则可以使⽤fopen打开/dev/zero⽂件,然后对该⽂件进⾏映射,可以同样达到匿名内存映射的效果。

参数offset:⽂件映射的偏移量,通常设置为0,代表从⽂件最前⽅开始对应,offset必须是分页⼤⼩的整数倍。

返回值:

若映射成功则返回映射区的内存起始地址,否则返回MAP_FAILED(-1),错误原因存于errno 中。

若映射成功则返回映射区的内存起始地址

错误代码:

EBADF 参数fd 不是有效的⽂件描述词

EACCES 存取权限有误。如果是MAP_PRIVATE 情况下⽂件必须可读,使⽤MAP_SHARED则要有PROT_WRITE以及该⽂件要能写⼊。

EINVAL 参数start、length 或offset有⼀个不合法。

EAGAIN ⽂件被锁住,或是有太多内存被锁住。

ENOMEM 内存不⾜。

* 系统调⽤mmap()⽤于共享内存的两种⽅式:

(1)使⽤普通⽂件提供的内存映射:

适⽤于任何进程之间。此时,需要打开或创建⼀个⽂件,然后再调⽤mmap()

典型调⽤代码如下:

fd=open(name, flag, mode); if(fd<0) ...

ptr=mmap(NULL, len , PROT_READ|PROT_WRITE, MAP_SHARED , fd , 0);

通过mmap()实现共享内存的通信⽅式有许多特点和要注意的地⽅,可以参看UNIX⽹络编程第⼆卷。

(2)使⽤特殊⽂件提供匿名内存映射:

适⽤于具有亲缘关系的进程之间。由于⽗⼦进程特殊的亲缘关系,在⽗进程中先调⽤mmap(),然后调⽤ fork()。那么在调⽤fork()之后,⼦进程继承⽗进程匿名映射后的地址空间,同样也继承mmap()返回的地址,这样,⽗⼦进程就可以通过映射区域进⾏通信了。注意,这⾥不是⼀般的继承关系。⼀般来说,⼦进程单独维护从⽗进程继承下来的⼀些变量。⽽mmap()返回的地址,却由⽗⼦进程共同维护。对于具有亲缘关系的进程实现共享内存最好的⽅式应该是采⽤匿名内存映射的⽅式。此时,不必指定具体的⽂件,只要设置相应的标志即可。

⼀. 概述

内存映射,简⽽⾔之就是将⽤户空间的⼀段内存区域映射到内核空间,映射成功后,⽤户对这段内存区域的修改可以直接反映到内核空间,相反,内核空间对这段区域的修改也直接反映⽤户空间。那么对于内核空间<---->⽤户空间两者之间需要⼤量数据传输等操作的话效率是⾮常⾼的。

⾸先,驱动程序先分配好⼀段内存,接着⽤户进程通过库函数mmap()来告诉内核要将多⼤的内存映射到内核空间,内核经过⼀系列函数调⽤后调⽤对应的驱动程序的file_operation中的mmap函数,在该函数中调⽤

remap_pfn_range()来建⽴映射关系。直⽩⼀点就是:驱动程序在mmap()中利⽤remap_pfn_range()函数将内核空间的⼀段内存与⽤户空间的⼀段内存建⽴映射关系。

⽤户空间mmap()函数:

void *mmap(void *start, length, int prot, int flags,int fd, off_t offset)

start:⽤户进程中要映射的某段内存区域的起始地址,通常为NULL(由内核来指定)

length:要映射的内存区域的⼤⼩

prot:期望的内存保护标志

flags:指定映射对象的类型

fd:⽂件描述符(由open函数返回)

offset:要映射的⽤户空间的内存区域在内核空间中已经分配好的的内存区域中的偏移。⼤⼩为PAGE_SIZE的整数倍

 

mmap方法

 1 #include <stdio.h>
 2 #include <unistd.h>
 3 #include <fcntl.h>
 4 #include <sys/mman.h>
 5 
 6 
 7 
 8 int main() {
 9 
10     int fd = open("./affinity.c", O_RDWR);
11 
12     //read(); write()
13 
14     unsigned char *addr = (unsigned char *)mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
15 
16     printf("affinity: %s\n", addr);
17 
18     int i = 0;
19 
20     for (i = 0;i < 20;i ++) {
21         *(addr+i) = 'A' + i;
22     }
23 
24 }

 

posted @ 2022-11-21 22:45  放弃吧  阅读(42)  评论(0编辑  收藏  举报