如何实现两个C主从程序共用的全局POSIX信号量跨进程同步
跨进程POSIX信号量同步实现方案
你当前代码使用的是进程内线程共享的无名信号量,sem_init第二个参数设为0的情况下,信号量只能在同一个进程的线程间可见,a.c和b.c是两个独立运行的进程,无法互相访问对方的信号量实例,同时writercount、readercount也是进程本地变量,两个进程各持有独立副本,判断逻辑完全失效。
要实现跨进程同步,需要改用有名POSIX信号量,同时把共享状态变量(readercount、writercount)放到共享内存中,修改方案如下:
1. a.c(主程序)修改后代码
#include <semaphore.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <pthread.h> #include <string.h> // 新增跨进程通信需要的头文件 #include <fcntl.h> #include <sys/mman.h> #include <sys/stat.h> sem_t *x,*y; // 改为信号量指针 pthread_t tid; pthread_t writerthreads[100],readerthreads[100]; int *readercount, *writercount; // 改为共享内存指针 void* reader(void* param) { if (*writercount > 0) { // 解引用共享变量 sem_wait(x); (*readercount)++; // 解引用共享变量 if (*readercount == 1) { // 解引用共享变量 sem_wait(y); } sem_post(x); printf("%d reader is inside\n",*readercount); // 解引用共享变量 //read all the files in the directory sleep(3); sem_wait(x); (*readercount)--; // 解引用共享变量 if (*readercount == 0) { // 解引用共享变量 sem_post(y); } sem_post(x); printf("%d Reader is leaving\n",*readercount+1); // 解引用共享变量 } else { printf("Nothing to view\n"); } return NULL; } void* writer(void* param) { printf("Master is trying to upload\n"); sem_wait(y); printf("Master is uploading\n"); //create file in a directory sem_post(y); (*writercount)++; // 解引用共享变量 printf("Master is leaving\n"); return NULL; } int main() { int a,i = 0,b; // 初始化共享内存存储readercount和writercount int shm_fd = shm_open("/shm_rwcount", O_CREAT | O_RDWR, 0666); ftruncate(shm_fd, 2 * sizeof(int)); void *shm_ptr = mmap(NULL, 2 * sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0); readercount = (int*)shm_ptr; writercount = (int*)shm_ptr + 1; *readercount = 0; *writercount = 0; // 创建有名信号量,天然支持跨进程访问 x = sem_open("/sem_x", O_CREAT | O_RDWR, 0666, 1); y = sem_open("/sem_y", O_CREAT | O_RDWR, 0666, 1); while (1) { printf("Enter 1 to View / 2 to Upload / 3 to Exit:"); scanf("%d",&b); if (b == 1) { pthread_create(&readerthreads[i],NULL,reader,NULL); } else if (b == 2) { pthread_create(&writerthreads[i],NULL,writer,NULL); } else { // 退出前清理资源 sem_close(x); sem_close(y); sem_unlink("/sem_x"); sem_unlink("/sem_y"); munmap(shm_ptr, 2 * sizeof(int)); shm_unlink("/shm_rwcount"); exit(0); } pthread_join(writerthreads[i],NULL); pthread_join(readerthreads[i],NULL); i++; } return 0; }
2. b.c(从程序)修改后代码
#include <semaphore.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <pthread.h> #include <string.h> // 新增跨进程通信需要的头文件 #include <fcntl.h> #include <sys/mman.h> #include <sys/stat.h> sem_t *x,*y; // 改为信号量指针 pthread_t tid; pthread_t readerthreads[100]; int *readercount, *writercount; // 改为共享内存指针 void* reader(void* param) { if (*writercount > 0) { // 解引用共享变量 sem_wait(x); (*readercount)++; // 解引用共享变量 if (*readercount == 1) { // 解引用共享变量 sem_wait(y); } sem_post(x); printf("%d Follower is inside\n",*readercount); // 解引用共享变量 //read all the files in the directory sleep(3); sem_wait(x); (*readercount)--; // 解引用共享变量 if (*readercount == 0) { // 解引用共享变量 sem_post(y); } sem_post(x); printf("%d Follower is leaving\n",*readercount+1); // 解引用共享变量 } else { printf("Nothing to view\n"); } return NULL; } int main() { int a,i = 0,b; // 打开主程序创建的共享内存 int shm_fd = shm_open("/shm_rwcount", O_RDWR, 0666); void *shm_ptr = mmap(NULL, 2 * sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0); readercount = (int*)shm_ptr; writercount = (int*)shm_ptr + 1; // 打开主程序创建的有名信号量 x = sem_open("/sem_x", O_RDWR); y = sem_open("/sem_y", O_RDWR); while (1) { printf("Enter 1 to View / 3 to Exit:"); scanf("%d",&b); if (b == 1) { pthread_create(&readerthreads[i],NULL,reader,NULL); } else { // 退出前清理资源 sem_close(x); sem_close(y); munmap(shm_ptr, 2 * sizeof(int)); exit(0); } pthread_join(readerthreads[i],NULL); i++; } }
3. 编译运行说明
- 两个程序编译时都需要加
-pthread和-lrt参数,示例编译命令:gcc a.c -o master -pthread -lrt gcc b.c -o follower -pthread -lrt - 运行顺序:先启动master主程序,再启动follower从程序
- 若程序异常退出导致信号量/共享内存残留,可手动删除
/dev/shm/路径下对应sem_x、sem_y、shm_rwcount文件后再重新运行
内容的提问来源于stack exchange,提问作者Checker Pecker
相关产品推荐
相关产品推荐

