解决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,但实际调用
write/read时传入的长度是sizeof(parent_msg)(指针的大小,通常为4或8字节),读写操作实际完成的字节数与判断值不匹配,直接触发错误退出。 - 缺少进程退出调用:在xv6中,
main函数执行完毕不会自动退出进程,父进程和子进程完成操作后未调用exit(0),可能导致后续异常。 - 管道交互逻辑异常:由于字节数判断错误,子进程会提前退出,父进程等待后执行读操作时也会因同样的判断失败触发错误。
修正方案
- 修正
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
相关产品推荐
相关产品推荐

