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

如何修复C语言中子进程管道通信日志器无输出问题?

管道通信日志器的子进程无输出问题修复

问题场景

尝试用C语言实现管道通信的日志器,父进程发送消息,子进程接收并打印,但运行时仅能看到父进程的printf输出,子进程无任何输出。调试发现子进程卡在第一个read语句,父进程写入操作无报错。

原代码

main函数

int main(void){
    spawn_logger();
    char wmsg[] = "Greetings";
    send_message(wmsg);
    strcpy(wmsg, "Hello");
    send_message(wmsg);
    kill_child();

    return 0;
}

spawn_logger函数

// global vars
pid_t pid;
int fd[2];

int spawn_logger() {
    if (pipe(fd) == -1) {
        printf("Pipe failed\n");
        return -1;
    }
    
    pid = fork();

    if (pid < 0) { // fork error
        printf("fork failed");
        return -1;
    }
    if (pid > 0) { // parent process
        close(fd[READ_END]);
        return 0; // return to main
    }
    // child process
    // spawn the receiver process
    log_message();
    // the receiver process will never reach this point
    return 0;
}

send_message函数

int send_message(char message[]){
    // do something with the message
    // e.g. write in a file
    printf("Message by parent sent: %s \n", message);

    // write the message to logger process
    int n = strlen(message) + 1;
    write(fd[WRITE_END], &n, sizeof(int));
    write(fd[WRITE_END], &message, sizeof(char) * strlen(message));

    return 0;
}

log_message和kill_child函数

// global vars
extern pid_t pid;
extern int fd[2];


int log_message(){
    //child process
    // will read from the pipe every time the parent process writes to it
    close(fd[WRITE_END]);

    int n;
    char *message;

    // read messages until parent process closes the pipe
    while (read(fd[READ_END], &n, sizeof(int)) > 0) {
        message = malloc(sizeof(char) * n);
        read(fd[READ_END], &message, sizeof(char) * n);
        printf("Message by logger received: %s \n", message);
    }

    close(fd[READ_END]);
    exit(0);
}


int kill_child(){
    close(fd[WRITE_END]);
    kill(pid, SIGKILL);
    return 0;
}

问题分析与修复

1. 管道读写的指针传递错误(核心问题)

  • send_message函数:write(fd[WRITE_END], &message, sizeof(char)*strlen(message));错误传递了数组指针的地址,而非数组内容的首地址。数组名message本身就是首地址,且需要写入包含\0的完整字符串,应改为write(fd[WRITE_END], message, n);。
  • log_message函数:read(fd[READ_END], &message, sizeof(char)*n);错误将数据写入指针变量message的地址,而非malloc分配的内存区域,应改为read(fd[READ_END], message, n);。

2. 子进程stdout缓冲问题

子进程的printf输出可能因全缓冲机制未即时刷新,导致看不到输出,需在printf后调用fflush(stdout);强制刷新缓冲区。

3. 内存泄漏问题

log_message中malloc的内存未释放,需在打印后调用free(message);避免泄漏。

4. 子进程终止逻辑优化

父进程关闭管道写端后,子进程的read会返回0,自动退出循环并正常终止,无需调用kill,可改为等待子进程正常退出。

修复后的代码

修复后的send_message

int send_message(char message[]){
    printf("Message by parent sent: %s \n", message);

    int n = strlen(message) + 1;
    write(fd[WRITE_END], &n, sizeof(int));
    // 传递数组首地址,写入包含\0的完整字符串
    write(fd[WRITE_END], message, n);

    return 0;
}

修复后的log_message

int log_message(){
    close(fd[WRITE_END]);

    int n;
    char *message;

    while (read(fd[READ_END], &n, sizeof(int)) > 0) {
        message = malloc(sizeof(char) * n);
        // 读取到malloc分配的内存区域
        read(fd[READ_END], message, n);
        printf("Message by logger received: %s \n", message);
        // 强制刷新输出缓冲区
        fflush(stdout);
        // 释放内存避免泄漏
        free(message);
    }

    close(fd[READ_END]);
    exit(0);
}

优化后的kill_child

int kill_child(){
    close(fd[WRITE_END]);
    // 等待子进程正常退出
    waitpid(pid, NULL, 0);
    return 0;
}

验证效果

修复后运行程序,会看到父进程和子进程的输出依次打印:

Message by parent sent: Greetings 
Message by logger received: Greetings 
Message by parent sent: Hello 
Message by logger received: Hello 

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 07:40:31