为何semop()返回EINVAL而非预期的EIDRM错误?
信号量移除后semop返回EINVAL而非EIDRM的原因分析
你的代码如下:
int rc = 0; key_t key = ftok("test.sh", 100); if (key == -1) { std::cout << "ftok failed" << std::endl; } int sem_id = semget(key, 1, IPC_CREAT | (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)); if (sem_id == -1) { std::cout << "semget failed" << std::endl; } //removing semaphore set union semun sem_union; rc = semctl(sem_id, 1, IPC_RMID, sem_union); if (rc == -1) { std::cout << "semctl failed" << std::endl; } struct sembuf command_buf[2]; // Wait for 0 command_buf[0].sem_num = 0; command_buf[0].sem_op = 0; command_buf[0].sem_flg = SEM_UNDO; // Increment by 1 command_buf[1].sem_num = 0; command_buf[1].sem_op = 1; command_buf[1].sem_flg = SEM_UNDO; rc = semop(sem_id, command_buf, 2); if (rc == -1) { std::cout << "errno=" << errno << std::endl; }
执行后输出errno=22(EINVAL),但预期返回EIDRM,核心原因是两个错误码的触发场景存在明确边界:
- EIDRM仅在阻塞阶段触发:当
semop()调用已经进入阻塞状态(比如你的代码中第一个操作是等待信号量值为0,若此时信号量不为0则会阻塞),在阻塞过程中信号量集被移除,才会返回EIDRM错误。 - EINVAL在无效标识符场景触发:你的代码是先调用
semctl(IPC_RMID)移除信号量集,再立刻执行semop()。此时sem_id已经是无效的标识符,内核优先校验sem_id的有效性,发现无效后直接返回EINVAL错误。
另外补充:你在semctl中传入的第二个参数1虽超出信号量有效编号范围(你创建的信号量集仅1个信号量,编号从0开始),但IPC_RMID命令会忽略该参数,因此semctl应该已成功移除信号量集,可通过检查semctl的返回值rc确认这一点。
内容的提问来源于stack exchange,提问作者vanti
相关产品推荐
相关产品推荐

