You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Linux下semop()调用不生效导致多进程同时进入临界区如何解决?

问题根因分析
  • ftok传参错误:ftok第一个参数必须是存在且可访问的文件路径,你传入空格会导致ftok调用失败返回-1,后续所有基于错误key的信号量操作都会失效。
  • 未创建信号量:semget(key,1,0)的第三个参数为0,代表仅获取已存在的信号量,首次运行时信号量不存在,semget直接返回无效的-1,你没有做错误判断,后续semop调用会直接报错返回,不会执行锁等待逻辑。
  • 未初始化信号量值:就算成功创建信号量,System V信号量默认初始值为0,要实现互斥锁逻辑需要将初始值设为1,否则第一次P操作(减1)会直接永久阻塞。
  • 缺少系统调用错误判断:所有ftok、semget、semop调用都没有判断返回值,无法感知调用失败的情况。
修复方案

修改要点

  1. 替换ftok的第一个参数为实际存在的文件路径,比如当前目录路径
  2. 调整semget的参数,添加IPC_CREAT | 0666权限位,保证信号量不存在时会主动创建
  3. 新增信号量初始化逻辑,首次创建信号量时将其值设为1
  4. 为所有系统调用添加错误判断逻辑

修正后代码

#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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.28 15:45:03