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

使用POSIX命名信号量同步父子进程遇阻塞问题求助

问题描述

尝试通过两个进程向文件写入0-100的递增数字,父进程写奇数,子进程写偶数,期望文件内容为:

1 2 3 4 5 6 ...... 100

采用POSIX命名信号量实现同步,但运行程序后仅输出进程启动提示,无数字输出,程序卡住:

####Parent#################
####Child#################
代码问题分析
  1. 信号量未跨进程共享打开:父进程仅打开s_odd信号量,子进程仅打开s_even信号量,导致双方调用对方信号量的sem_post/sem_wait时,使用未初始化的野指针,触发未定义行为,直接导致进程卡住。
  2. 信号量创建冲突:双方都使用O_CREAT | O_EXCL标志,若一方先创建信号量,另一方会因O_EXCL导致sem_open失败,无法获取信号量句柄。
  3. 文件缓冲区未刷新:父子进程拥有独立的文件指针缓冲区,写入后未刷新会导致内容无法立即写入文件,甚至出现输出错位。
  4. 循环逻辑冗余:原代码循环中每次判断奇偶,增加不必要的分支,结合信号量初始化逻辑,可直接遍历目标数字类型优化流程。
修复方案
  1. 统一信号量打开逻辑:父子进程都打开两个信号量,由父进程负责初始化信号量值,子进程直接打开已存在的信号量。
  2. 移除O_EXCL标志:避免创建信号量时的冲突,确保后续进程能正常打开已存在的信号量。
  3. 写入后刷新文件缓冲区:每次fprintf后调用fflush(ptr),确保内容立即写入文件,避免缓冲区问题。
  4. 优化循环逻辑:直接遍历奇数/偶数,减少分支判断,提高代码效率。
  5. 规范信号量生命周期:父进程在子进程退出后再清理信号量,避免子进程仍在使用时信号量被提前删除。
修复后的完整代码
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <semaphore.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/wait.h>

FILE *ptr;
sem_t *s_even, *s_odd;
const char *even_sem = "even_sem", *odd_sem = "odd_sem";

void fileWR();
void parent();
void child();

int main(void) {
    ptr = fopen("Semaphore.txt", "w+");
    if (ptr == NULL) {
        fprintf(stderr, "Failed to open file!\n");
        exit(EXIT_FAILURE);
    }
    fileWR();
    return 0;
}

void fileWR() {
    // 清理残留的旧信号量
    sem_unlink(even_sem);
    sem_unlink(odd_sem);

    // 父进程创建并初始化信号量:s_even初始1让子进程先写,s_odd初始0让父进程等待
    s_even = sem_open(even_sem, O_CREAT, 0644, 1);
    s_odd = sem_open(odd_sem, O_CREAT, 0644, 0);
    
    if (s_even == SEM_FAILED || s_odd == SEM_FAILED) {
        perror("sem_open failed");
        exit(EXIT_FAILURE);
    }

    pid_t pid = fork();
    if (pid == -1) {
        perror("fork failed");
        exit(EXIT_FAILURE);
    }

    if (pid != 0) {
        puts("####Parent#################");
        parent();
        wait(NULL);
        // 父进程最后清理资源
        sem_close(s_even);
        sem_close(s_odd);
        sem_unlink(even_sem);
        sem_unlink(odd_sem);
        fclose(ptr);
    } else {
        // 子进程打开已存在的信号量
        s_even = sem_open(even_sem, 0);
        s_odd = sem_open(odd_sem, 0);
        if (s_even == SEM_FAILED || s_odd == SEM_FAILED) {
            perror("child sem_open failed");
            exit(EXIT_FAILURE);
        }
        puts("####Child#################");
        child();
        sem_close(s_even);
        sem_close(s_odd);
        fclose(ptr);
        exit(EXIT_SUCCESS);
    }
}

void parent() {
    // 直接遍历所有奇数
    for (int i = 1; i <= 100; i += 2) {
        sem_wait(s_odd);
        fprintf(ptr, "%d ", i);
        printf("i=%d ", i);
        fflush(ptr); // 强制刷新缓冲区
        sem_post(s_even);
    }
}

void child() {
    // 直接遍历所有偶数
    for (int j = 0; j <= 100; j += 2) {
        sem_wait(s_even);
        fprintf(ptr, "%d ", j);
        printf("j=%d ", j);
        fflush(ptr); // 强制刷新缓冲区
        sem_post(s_odd);
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 12:28:20