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

解决MIT 6.828 xv6 PingPong实验管道文件描述符写入错误

Ping-Pong管道通信问题修复

背景

需要编写一个使用UNIX系统调用的程序,通过一对单向管道在两个进程间“ping-pong”数据:

  • 父进程向子进程发送数据
  • 子进程打印 <pid>: received ping(pid为自身进程ID),将数据写回管道后退出
  • 父进程读取子进程发来的数据,打印 <pid>: received pong 后退出

待解决代码

#include "kernel/types.h"
#include "kernel/stat.h"
#include "user.h"

void main(int argc, char* argv[]){
    int pid;
    int file_desc[2];
    
    char *parent_msg = "parent_msg";
    char *child_msg = "child_msg";

    if(pipe(file_desc) < 0){
        exit(1);
    }
    
    if(0 > (pid = fork())){
        exit(1);
    }

    if(pid > 0){
        // parent process
        char* buffer = malloc(strlen(child_msg) + 1);

        if (write(file_desc[1], parent_msg, sizeof(parent_msg)) != 1){
            fprintf(2, "Can't write to child\n");
            exit(1);
        }
        close(file_desc[1]);

        // wait child to receive from parent
        wait(0);

        if (read(file_desc[0], buffer, sizeof(child_msg)) != 1){
            fprintf(2, "Can't read from child\n");
            exit(1);
        }
        close(file_desc[0]);
        printf("%d received pong\n", getpid());

    } else{
        // child process
        char* buffer = malloc(strlen(parent_msg) + 1);

        if (read(file_desc[0], buffer, sizeof(parent_msg)) != 1){
            fprintf(2, "Can't read from parent\n");
            exit(1);
        }
        printf("%d received ping\n", getpid());
        close(file_desc[0]);

        if (write(file_desc[1], child_msg, sizeof(child_msg)) != 1){
            fprintf(2, "Can't write to parent\n");
            exit(1);
        }
        close(file_desc[1]);
    }
}

运行错误

运行程序后,xv6终端输出如下错误:

$ pingpong
Can't write to child
Can't read from parent

问题分析

你猜测的write(file_desc[1], parent_msg, 11) != 1确实是核心问题,具体错误点包括:

  1. 字节数判断不匹配:代码中判断读写是否成功的条件是返回值等于1,但实际调用write/read时传入的长度是sizeof(parent_msg)(指针的大小,通常为4或8字节),读写操作实际完成的字节数与判断值不匹配,直接触发错误退出。
  2. 缺少进程退出调用:在xv6中,main函数执行完毕不会自动退出进程,父进程和子进程完成操作后未调用exit(0),可能导致后续异常。
  3. 管道交互逻辑异常:由于字节数判断错误,子进程会提前退出,父进程等待后执行读操作时也会因同样的判断失败触发错误。

修正方案

  • 修正read/write的返回值判断条件,改为与实际传入的消息长度(sizeof(msg))比较
  • 在父进程和子进程代码末尾添加exit(0),确保进程正常退出
  • xv6系统不识别stderr,保留fprintf(2, ...)的写法(文件描述符2对应标准错误输出)

修正后的代码

#include "kernel/types.h"
#include "kernel/stat.h"
#include "user.h"

void main(int argc, char* argv[]){
    int pid;
    int file_desc[2];
    
    char *parent_msg = "parent_msg";
    char *child_msg = "child_msg";

    if(pipe(file_desc) < 0){
        exit(1);
    }
    
    if(0 > (pid = fork())){
        exit(1);
    }

    if(pid > 0){
        // parent process
        char* buffer = malloc(strlen(child_msg) + 1);

        if (write(file_desc[1], parent_msg, sizeof(parent_msg)) != sizeof(parent_msg)){
            fprintf(2, "Can't write to child\n");
            exit(1);
        }
        close(file_desc[1]);

        // wait child to receive from parent
        wait(0);

        if (read(file_desc[0], buffer, sizeof(child_msg)) != sizeof(child_msg)){
            fprintf(2, "Can't read from child\n");
            exit(1);
        }
        close(file_desc[0]);
        printf("%d received pong\n", getpid());
        exit(0);

    } else{
        // child process
        char* buffer = malloc(strlen(parent_msg) + 1);

        if (read(file_desc[0], buffer, sizeof(parent_msg)) != sizeof(parent_msg)){
            fprintf(2, "Can't read from parent\n");
            exit(1);
        }
        printf("%d received ping\n", getpid());
        close(file_desc[0]);

        if (write(file_desc[1], child_msg, sizeof(child_msg)) != sizeof(child_msg)){
            fprintf(2, "Can't write to parent\n");
            exit(1);
        }
        close(file_desc[1]);
        exit(0);
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 06:52:49