Linux下semop()调用不生效导致多进程同时进入临界区如何解决?
问题根因分析
ftok传参错误:ftok第一个参数必须是存在且可访问的文件路径,你传入空格会导致ftok调用失败返回-1,后续所有基于错误key的信号量操作都会失效。- 未创建信号量:
semget(key,1,0)的第三个参数为0,代表仅获取已存在的信号量,首次运行时信号量不存在,semget直接返回无效的-1,你没有做错误判断,后续semop调用会直接报错返回,不会执行锁等待逻辑。 - 未初始化信号量值:就算成功创建信号量,System V信号量默认初始值为0,要实现互斥锁逻辑需要将初始值设为1,否则第一次P操作(减1)会直接永久阻塞。
- 缺少系统调用错误判断:所有
ftok、semget、semop调用都没有判断返回值,无法感知调用失败的情况。
修复方案
修改要点
- 替换
ftok的第一个参数为实际存在的文件路径,比如当前目录路径 - 调整
semget的参数,添加IPC_CREAT | 0666权限位,保证信号量不存在时会主动创建 - 新增信号量初始化逻辑,首次创建信号量时将其值设为1
- 为所有系统调用添加错误判断逻辑
修正后代码
#include<stdio.h> #include<unistd.h> #include<sys/sem.h> #include<sys/types.h> #include<sys/ipc.h> #include<errno.h> int main(void) { key_t key; int semid; // 第一个参数替换为实际存在的路径,此处用当前目录 key = ftok("./", 'a'); if (key == -1) { perror("ftok调用失败"); return 1; } // 添加IPC_CREAT标识,不存在则创建信号量,权限设为0666 semid = semget(key, 1, IPC_CREAT | 0666); if (semid == -1) { perror("semget调用失败"); return 1; } // 仅首次创建时初始化信号量值为1,避免重复初始化覆盖现有值 int sem_val = semctl(semid, 0, GETVAL); if (sem_val == 0) { if (semctl(semid, 0, SETVAL, 1) == -1) { perror("semctl初始化信号量失败"); return 1; } } struct sembuf buf = {0, -1, 0}; printf("Before entering into the critical section\n"); printf("Waiting for unlock\n"); if (semop(semid, &buf, 1) == -1) { perror("semop加锁失败"); return 1; } printf("Enter the critical section\n"); printf("Enter to unlock\n"); getchar(); buf.sem_op = 1; if (semop(semid, &buf, 1) == -1) { perror("semop解锁失败"); return 1; } // 不需要保留信号量时可添加删除逻辑:semctl(semid, 0, IPC_RMID); return 0; }
注意:测试完成后如果不需要保留信号量,可以手动执行
ipcrm -s <信号量ID>删除残留的System V信号量,避免影响后续测试。
内容的提问来源于stack exchange,提问作者Rishabh Talwar
相关产品推荐
相关产品推荐

