C使用select并从管道读取

时间:2011-10-16 21:56:32

标签: c select pipe

我有一个正在处理的程序,我使用select来从管道中进行选择。

问题是我正在使用if(FD_ISSET(pfd[i][0], &read_set))并且验证失败,因为FD_ISSET返回0,但如果我尝试使用read(pfd[i][0],&c,sizeof(c))读取它将正常工作并且来自pfd的内容[pfd] 0]与我想要的pfd [1]不同。

我想知道到底发生了什么,因为FD_ISSET返回0但我实际上可以从中读取内容

修改

全局变量CORES将控制我创建的进程数 下一个代码将创建管道并使用FD_SET来设置位

for(i=0; i<CORES; i++)
{
    if(pipe(pfd[i])==-1)
        perror("Ocorreu um erro a criar um pipe");

    FD_SET(pfd[i][0], &read_set);
}

read_set是在main()启动后立即定义的。我在上面的代码之后使用for()来使用fork()(x = CORES)

创建x进程

然后这部分在父进程中运行:

    while (x<CORES){
    int selec = select(pfd[CORES-1][0]+1, &read_set, NULL, NULL, NULL);

    if(selec>0)
    {
        if(FD_ISSET(pfd[x][0], &read_set))
        {
            close(pfd[x][1]);

            if(read(pfd[x][0],&c,sizeof(c))==-1)
                perror("Ocorreu um erro a ler do pipe");

            printf("c= %f \n",c);
            c_final+=c;
            x++;
        }
        else
            printf("\nFile descriptor pfd[%d][0] is not set\n",x);

    }
    else if(selec == -1)
        perror("Ocorreu um erro no select");
}

这个问题是FD_ISSET(pfd[x][0], &read_set)不会传递,因为它没有为pfd [0]设置,但它可以用于pfd [1],反之亦然(因为我不知道它是否会失败为0或1)

EDIT2:

select()为read_set中的文件描述符数返回一个int。我将CORES设置为2,因此它创建了2个进程和2个管道,并在read_set中设置了2位。我的select()返回int 1.它是否应该返回int 2或0计数(所以它将是0和1 = 2)?

2 个答案:

答案 0 :(得分:5)

select的第一个参数应该是1+max_fd。虽然pfd[CORES-1][0]可能是最大的,但不能保证。您可以在填充read_set时计算最大的文件描述符,并将其用于select来电。

此外,您需要在每次拨打read_set之前重新填充select。因此,while循环之外的for循环需要进入。实际上,最好将select移到外部,然后用for循环设置read_set并在另一个循环中的while循环之后结束来封闭块 - 这样,在每次选择返回时,您都可以处理所有已发信号的描述符,而无需再次进行选择。


编辑:澄清我对循环的意义:每次选择返回时都应检查所有描述符。但是你不能只选择一次选择,因为不能保证一次就能准备好所有答案。所以你做了类似的事情:

for (i=0; i != CORES; ++i)
{
  // Call pipe() and populate pfd[i]
}

while (!finished) // Need a proper condition to terminate this loop
{
    // Setup read_set
    FD_ZERO(&read_set);
    for (i=0; i != CORES; ++i)
    {
        FD_SET(pfd[i][0], &read_set);
        // find max_fd here
    }
    // select here
    if (select(max_fd+1, blahblah) > 0)
    {
        for (i=0; i != CORES; ++i) // This used to be while(x < CORES). But a for loop would do
        {
            // Check the fd, and process
        }
    }
    else
    {
         // error in select
    }
}

答案 1 :(得分:1)

我建议在这种情况下,使用所有这些不同的文件描述符,你试图读取并检查非阻塞写入(也就是说,你似乎在尝试检查是否有任何结束管道处于活动状态),除非出于某种原因必须使用poll(),否则请使用select()而不是select()。使用轮询,您只需在struct pollfd的数组中设置所有文件描述符,并为它们提供您要测试的事件。然后poll()返回后的结果将告诉您有多少文件描述符有事件。我认为这种方法可以让您更轻松地管理您拥有的内容。例如,您可以执行以下操作:

struct pollfds descriptors[CORES * 2] = {0};

for(int i=0; i<CORES; i++)
{
    if(pipe(pfd[i])==-1)
        perror("Ocorreu um erro a criar um pipe");

    //wait for either a read on pipe[0] or a non-blocking write on pipe[1]
    descriptors[i*2].fd = pfd[i][0];
    descriptors[i*2].events = POLLIN;
    descriptors[(i*2)+1].fd = pdf[i][1];
    descriptors[(i*2)+2].events = POLLOUT;
}

while (x < CORES)
{
    int num_events = poll(descriptors, CORES * 2, -1); //infinite timeout period

    //...check your descriptors array for events
}