开发者

C use select and read from pipe

开发者 https://www.devze.com 2023-04-13 04:42 出处:网络
I\'ve got a program that I\'m working on and I use select to choose from the pipes to read. The problem is that I\'m using if(FD_ISSET(pfd[i][0], &read_set)) and it fails the verification because

I've got a program that I'm working on and I use select to choose from the pipes to read.

The problem is that I'm using if(FD_ISSET(pfd[i][0], &read_set)) and it fails the verification because FD_ISSET is returning 0, but if I try to read using read(pfd[i][0],&c,sizeof(c)) it will work fine and the contents from pipe pfd[0] are different from pfd[1] like I want.

I want to know what the hell is going on because FD_ISSET returns 0 but I can actually read content from it

EDIT

The global variable CORES will control how much processes I create The next code will create the pipes and use FD_SET to set the bits

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 is defined right after main() starts. I use for() right after the above code to create x processes using fork() (x = CORES)

then this part runs in father process:

    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");
}

the problem with this is that FD_ISSET(pfd[x][0], &read_set) will not pass because it is not set for pfd[0] but it can be for pfd[1] or vice-versa (because I don't know if it will fail for 0 or 1)

EDIT2:

select() returns an int for the number of file descriptors in read_set. I 开发者_开发问答have CORES set to 2 so it creates 2 processes and 2 pipes and sets 2 bits in read_set. my select() is returning int 1. should it be returning int 2 or 0 counts as well (so it would be 0 and 1 = 2)?


First argument of select is supposed to be 1+max_fd. While it is likely that pfd[CORES-1][0] is the largest, it is not guaranteed. You could calculate the largest file descriptor when you are populating the read_set, and use that for your select call.

Also, you need to re-populate the read_set before you call select every single time. So the for loop outside the while loop needs to come in. Actually, it is better to move the select outside, and enclose the block starting with the for loop setting up the read_set and ending after the while loop in another loop - so that at every select return, you process all signaled descriptors without going into select again.


EDIT: To clarify what I meant about the loops: you should check all descriptors every time select returns. But you cannot call select only once, as there are no guarantees that all answers will be ready at once. So you do something like:

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
    }
}


I'd suggest in this scenario, with all these different file-descriptors you're trying to read from and check for non-blocking writes on (i.e., it seems like you're trying to check if any end of a pipe is active), that you go with poll() rather than select() unless for some reason you must use select(). With poll you can simply setup all your file-descripors in an array of struct pollfd's, and give them the events your looking to test for. Then the results of poll() after it returns will let you know how many of your file-descriptors have events. I think that approach will be a lot easier for you to manage with what you have here. For instance, you could do something like the following:

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
}
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号