C语言多进程非阻塞管道编译错误修复及正确性咨询
C多进程管道通信问题:编译错误修复与非阻塞设置验证
问题描述
我正在开发一个C语言程序,包含1个父进程和3个子进程。需求是父进程与每个子进程通过两个管道建立连接,当子进程需要向兄弟进程发送消息时,先将消息发送给父进程,再由父进程转发至目标子进程,且父进程的管道读端需设置为非阻塞模式。
参考示例代码后出现以下编译错误:
array type has incomplete element type 'int[]' void parent_read(int pipes[][]) (line 11)
type of formal parameter is incomplete parent_read(pipes); (line140)
请问如何修复这些错误?另外,我当前的非阻塞设置是否正确?
相关代码
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <errno.h> #include <fcntl.h> #include <sys/wait.h> #include <time.h> #define MSGSIZE 5 void parent_read(int pipes[][]) { int nread; char buf[MSGSIZE]; // write link close(pipes[1]); while (1) { // read call if return -1 then pipe is // empty because of fcntl nread = read(pipes[0], buf, MSGSIZE); switch (nread) { case -1: // case -1 means pipe is empty and errono // set EAGAIN if (errno == EAGAIN) { printf("(pipe empty)\n"); sleep(1); break; } else { perror("read"); exit(4); } // case 0 means all bytes are read and EOF(end of conv.) case 0: printf("End of conversation\n"); // read link close(pipes[0]); exit(0); default: // text read // by default return no. of bytes // which read call read at that time printf("MSG = %s\n", buf); } } } int main() { int pids[3],id[3]; int pipes[6][2]; int i; for (i=0;i<6;i++) { if (pipe(pipes[i])==-1) { printf("Error in pipe: %d\n",i); return 0; } else { printf("Error in pipe:!\n"); } } if (fcntl(pipes[0][0], F_SETFL, O_NONBLOCK) < 0) { exit(2); } for(i=0;i<3;i++) { pids[i]=fork(); if(pids[i]==0) { id[i]=getpid(); //printf("ID:%d\n",id[i]); break; } } if (getpid()==id[0]) { for (i=0;i<6;i++) { if (i>0 && i>1) { close(pipes[i][0]); close(pipes[i][1]); printf("Pipes of A have closed:%d\n",i); } } /* char* x="hello"; if (write(pipes[1][1],&x,sizeof(int)) == -1) { printf("error in write"); }*/ return 0; } if (getpid()==id[1]) { for (i=0;i<6;i++) { if ((i>2 && i>3) || (i<2 && i<3)) { close(pipes[i][0]); close(pipes[i][1]); printf("Pipes of B have closed:%d\n",i); } } return 0; } if (getpid()==id[2]) { for (i=0;i<6;i++) { if (i<4 && i<5) { close(pipes[i][0]); close(pipes[i][1]); printf("Pipes of C have closed:%d\n",i); } } return 0; } if(getpid()!=0) { // char y; parent_read(pipes); //Here i try to call parent read //read(pipes[1][0],&y,sizeof(int)); //printf("The child processe has given:%y",y); for(i=0;i<=3;i++) { wait(NULL); } printf("PARENT:%d\n",getpid()); } }
问题解答
1. 编译错误修复
C语言传递二维数组作为函数参数时,必须明确指定第二维的大小——编译器需要这个信息来计算内存偏移,确定数组元素的访问方式。你的parent_read函数参数int pipes[][]未指定第二维大小,导致编译器无法识别元素类型,触发报错。
修复方式有两种:
- 方式一:明确第二维大小
由于你的pipes是int[6][2]类型,直接在函数参数中声明第二维大小:void parent_read(int pipes[][2]) - 方式二:使用数组指针
用指针形式更清晰地表示参数类型,效果与方式一一致:void parent_read(int (*pipes)[2])
同时,parent_read函数内部还有两处逻辑错误需要修正:
close(pipes[1]);:pipes[1]是数组,close需要传入文件描述符,你需要明确指定要关闭的管道端(比如pipes[1][1]表示第二个管道的写端)。nread = read(pipes[0], buf, MSGSIZE);:同理,pipes[0]是数组,应改为pipes[0][0](第一个管道的读端),且后续需要遍历所有子进程的读端来处理数据,而非仅处理第一个管道。
2. 非阻塞设置验证
当前代码仅对pipes[0][0]设置了非阻塞模式,但你的需求是父进程监听所有3个子进程的管道读端,因此需要为每个父进程需要读取的管道读端都设置非阻塞属性。
正确的设置方式:
- 遍历所有需要监听的读端(假设每个子进程对应一个父进程读的管道,比如索引0、2、4的管道读端):
- 先获取文件描述符原有标志,再添加
O_NONBLOCK,避免覆盖原有属性:
for (i = 0; i < 6; i += 2) { int flags = fcntl(pipes[i][0], F_GETFL, 0); if (flags == -1) { perror("fcntl get failed"); exit(2); } if (fcntl(pipes[i][0], F_SETFL, flags | O_NONBLOCK) == -1) { perror("fcntl set failed"); exit(2); } }
额外建议
- 子进程关闭管道的逻辑存在错误:比如第一个子进程的判断
i>0 && i>1等价于i>1,会关闭索引2-5的管道,但应该只保留与父进程通信的两个管道,关闭其他无关管道。 - 父进程处理多管道读取时,建议使用
select或poll系统调用同时监听多个非阻塞管道,避免循环sleep浪费CPU资源。
内容的提问来源于stack exchange,提问作者Niko
相关产品推荐
相关产品推荐

