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

基于SystemV信号量与共享内存的Server-Clients同步问题排查

问题分析与修复方案

1. 多服务器进程引发冲突

你的主循环里,每fork一个客户端,父进程就进入服务器处理逻辑。这会生成N个服务器进程,它们同时争抢共享内存和信号量,直接导致临界区冲突。服务器应该是单个进程,等所有客户端fork完成后,统一处理所有请求。

2. 共享内存空间不足

创建共享内存时用了sizeof(int),但实际要存的是struct SharedData结构体,空间不够会导致数据越界覆盖,引发混乱:

// 错误代码
shm_id = shmget(IPC_PRIVATE, sizeof(int), IPC_CREAT | 0660);
// 修复后
shm_id = shmget(IPC_PRIVATE, sizeof(struct SharedData), IPC_CREAT | 0660);

3. 信号量同步逻辑完全颠倒

服务器端的信号量操作顺序搞反了,正确的同步流程应该是:

  • 客户端:填好请求数据 → sem_V(sem_id, 1)(通知服务器有请求)→ sem_P(sem_id, 0)(等服务器处理完)
  • 服务器:sem_P(sem_id, 1)(等客户端发请求)→ 处理请求 → sem_V(sem_id, 0)(通知客户端处理完成)

你的服务器先执行sem_V(sem_id, 0)再sem_P(sem_id, 1),客户端还没发请求就被唤醒,完全失去同步作用。

4. 随机数未初始化

用rand()前没调用srand(),所有进程生成的随机数序列完全一样,不符合测试预期。可以在客户端进程开头加:

srand(getpid()); // 用进程PID当随机种子

5. 信号量资源释放错误

free_resources里逐个删除信号量是错的,直接删除整个信号量集就行:

void free_resources(int shm_id, int sem_id) {
    shmctl(shm_id, IPC_RMID, NULL);
    semctl(sem_id, IPC_RMID, 0); // 删除整个信号量集
}

修复后的核心代码片段

主函数(单个服务器进程)

// 先fork所有客户端
for (int i = 0; i < N; i++) {
    sleeptime = random() % 10;
    if ((pid = fork()) == -1) {
        perror("fork");
        free_resources(shm_id, sem_id);
        exit(EXIT_FAILURE);
    }
    if (pid == 0) {
        srand(getpid());
        printf("# I am the child process with process id: %d\n", getpid());
        int j = 0;
        while (j < data->max_requests) {
            data->file_index = rand() % MAX_FILES + 1;
            data->start_line = rand() % MAX_LINES + 1;
            data->end_line = rand() % (MAX_LINES - data->start_line) + data->start_line;
            printf("(%d): Client %d request %d\n", getpid(), i, j);
            data->client_request = j+1;
            sem_V(sem_id, 1); // 通知服务器有请求

            sem_P(sem_id, 0); // 等服务器处理完
            printf("(%d): Server processed request %d\n", getpid(), j);
            j++;
            printf("j is %d \n",j);
        }
        exit(EXIT_SUCCESS);
    }
}

// 单个服务器处理所有请求
int total_requests = N * L;
int processed = 0;
while (processed < total_requests) {
    sem_P(sem_id, 1); // 等客户端请求
    printf("# I am the server process with process id: %d\n", getpid());
    printf("(%d): processing client request %d\n", getpid(), processed+1);
    strcpy(data->shared_memory, "Response from server");
    sem_V(sem_id, 0); // 通知客户端处理完成
    processed++;
}

// 等所有客户端退出
for (int i = 0; i < N; i++) {
    wait(NULL);
}

关键说明

  • 必须保证只有一个服务器进程,避免多进程争抢资源。
  • 严格遵守信号量同步顺序,别搞反等待和通知的时机。
  • 共享内存大小要足够存整个结构体,防止数据越界。

内容的提问来源于stack exchange,提问作者Yourias

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 17:44:52