macOS下POSIX信号量报错‘Semaphore closing failed: Bad file descriptor’排查
错误原因分析
- 同名命名信号量的冲突:POSIX命名信号量是系统全局的,同一个名称在系统中只能对应一个实例。你用
"/my_semaphore"重复三次调用sem_open,第一次创建成功后,后续两次实际是打开同一个已存在的信号量,而非创建新的。当你尝试关闭这三个指向同一信号量的句柄时,若其中某次关闭已经释放了文件描述符,后续重复关闭就会触发「Bad file descriptor」错误。 - macOS信号量接口限制:macOS对无名信号量的
sem_init/sem_destroy支持有限,改用命名信号量的sem_open/sem_close是正确方向,但参数使用不符合规范。
信号量打开参数的正确用法
- 名称必须唯一:每个信号量要使用不同的系统级名称,比如
"/my_sem_1"、"/my_sem_2"、"/my_sem_3",避免冲突。 sem_open参数规范:- 名称必须以
/开头(POSIX标准强制要求,macOS严格执行)。 - 创建新信号量时,用
O_CREAT | O_EXCL组合标志,确保信号量不存在时才创建,避免意外复用旧实例;仅打开已有信号量时用O_RDWR。 - 权限位设为
0644这类合理值,保证进程有访问权限。 - 初始值根据业务需求设置(比如同步信号量设1,资源信号量设对应资源数)。
- 名称必须以
修复代码示例
正确的初始化与销毁函数:
#include <semaphore.h> #include <stdio.h> #include <fcntl.h> #include <sys/stat.h> sem_t* init_semaphore(const char* name, unsigned int value) { sem_t* sem = sem_open(name, O_CREAT | O_EXCL, 0644, value); if (sem == SEM_FAILED) { perror("Semaphore creation failed"); return NULL; } return sem; } void cleanup_semaphore(sem_t* sem, const char* name) { if (sem != SEM_FAILED) { if (sem_close(sem) == -1) { perror("Semaphore closing failed"); } // 必须unlink删除系统中的信号量条目,否则下次启动会残留 if (sem_unlink(name) == -1) { perror("Semaphore unlinking failed"); } } }
调用时使用不同名称:
sem_t* sem1 = init_semaphore("/my_sem_1", 1); sem_t* sem2 = init_semaphore("/my_sem_2", 0); sem_t* sem3 = init_semaphore("/my_sem_3", 1); // 业务逻辑... cleanup_semaphore(sem1, "/my_sem_1"); cleanup_semaphore(sem2, "/my_sem_2"); cleanup_semaphore(sem3, "/my_sem_3");
内容的提问来源于stack exchange,提问作者AndreasKaram
相关产品推荐
相关产品推荐

