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

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个子进程的管道读端,因此需要为每个父进程需要读取的管道读端都设置非阻塞属性。

正确的设置方式:

  1. 遍历所有需要监听的读端(假设每个子进程对应一个父进程读的管道,比如索引0、2、4的管道读端):
  2. 先获取文件描述符原有标志,再添加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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 16:04:53