进程间通信:共享内存+互斥锁
上一篇进程间通信:共享内存没有实现互斥锁保护,今天用信号量实现一个进程间互斥锁,保护共享变量的修改。
参考资料:
http://man7.org/linux/man-pages/man7/sem_overview.7.html
http://man7.org/linux/man-pages/man3/sem_init.3.html
http://man7.org/linux/man-pages/man3/sem_post.3.html
http://man7.org/linux/man-pages/man3/sem_wait.3.html
http://man7.org/linux/man-pages/man3/sem_destroy.3.html
实现思路:父进程开辟一段共享内存,将开始sizeof(sem_t)大小作为互斥锁存储空间,在父进程中映射这一段内存,在之后fork的子进程将会继承这一映射关系,进而实现进程间共享互斥锁。
代码实现:
#include <stdio.h> #include <fcntl.h> #include <stdlib.h> #include <unistd.h> #include <sys/types.h> #include <sys/mman.h> #include <sys/stat.h> #include <semaphore.h> #define MAPPING_SIZE 4096 int main (int argc,char* argv[]){ int mapfd; const char* mapname = "/number"; // 开辟一段共享内存 mapfd = shm_open(mapname,O_RDWR|O_CREAT,S_IRUSR | S_IWUSR); if(mapfd == -1){ perror("shm_open fail"); exit(EXIT_FAILURE); } // ftruncate可以用来设置共享内存到指定大小 if(ftruncate(mapfd,MAPPING_SIZE) == -1){ perror("ftruncate fail"); close(mapfd); exit(EXIT_FAILURE); } // 将共享内存开始处作为进程间互斥锁 void* sp = mmap(NULL,MAPPING_SIZE,PROT_READ|PROT_WRITE,MAP_SHARED,mapfd,0); if(sp == NULL){ perror("mmap fail"); close(mapfd); exit(EXIT_FAILURE); } sem_t* mutex = (sem_t*)sp; if(sem_init(mutex,1,1) != 0) { perror("sem_init fail"); close(mapfd); exit(EXIT_FAILURE); } int * num = (int*)(sp+sizeof(sem_t)); int stat,cid,n,procCount=0,maxProcCount=8; for(n = 0;n<maxProcCount;++n){ cid = fork(); if (cid == -1){ perror("fork fail"); continue; } if(cid == 0){ sem_wait(mutex); (*num)++; sem_post(mutex); printf("Process %d: %d\n",getpid(),*num); if(munmap(sp,MAPPING_SIZE) == -1){ perror("munmap fail"); } close(mapfd); _exit(EXIT_SUCCESS); } ++procCount; } while(procCount--){ cid = wait(&stat); if(cid == -1){ perror("wait fail"); break; } printf("%d cid %d exit.\n",procCount,cid); } sem_destroy(mutex); close(mapfd); // 如果不执行shm_unlink则多次执行程序的输出是递增的,共享内存被重复利用了 shm_unlink(mapname); }
运行效果:
[root@centos7 c]# gcc -lrt -pthread process.c -o process [root@centos7 c]# ./process Process 11086: 1 Process 11087: 2 Process 11088: 3 Process 11089: 4 Process 11090: 5 Process 11092: 6 7 cid 11086 exit. 6 cid 11087 exit. 5 cid 11088 exit. 4 cid 11089 exit. 3 cid 11090 exit. 2 cid 11092 exit. Process 11093: 7 Process 11091: 8 1 cid 11093 exit. 0 cid 11091 exit.