使用select()函数与管道

4
创建一个二进制进程树,向下发送信息,然后将值发送回上层,随着升级而聚合信息的思想。
我遇到的问题是使用 select() 确定管道何时可以读取。到目前为止,我所写的代码中,第一个管道(第一左子节点)能够接收信息并打印输出;但是第二个管道(第一右子节点)在接收任何信息之前就超时了。我不知道为什么,因为第一个管道工作得非常好。
每个子进程最终都会创建自己的子进程,如果没有更好地掌握 select(),我甚至无法开始这个过程。
int bit_count(char *passed, int len){
//initialize file descriptors
int fd1[2] = {1, 2};
int fd2[2] = {3, 4};

fd_set read_set;
fd_set write_set;

//set timeval structure for timeout
struct timeval tv;
tv.tv_sec = 10;
tv.tv_usec = 0;

FD_ZERO(&read_set);             //clear the set
FD_SET(fd1[0], &read_set);      //add first file descriptor to set
FD_SET(fd2[0], &read_set);      //add second file descriptor to set

//open the pipes
pipe(fd1);
pipe(fd2);

//fork a child process
pid_t kid = fork();
if(kid == -1) printf("forking failed.");

if (kid == 0){  //first child process
    int status = 1;
    while(status){
        int retval = select(fd1[0]+1, &read_set, NULL, NULL, &tv);

        switch(retval) {
                case -1:
                        printf("Select Error.\n");
                        exit (-1);
                        status = 0;
                        break;

                case 0:
                        printf("Timeout...");
                        status = 0;
                        break;

                default:
                        if (FD_ISSET(fd1[0], &read_set)) {
                            char *lstring = malloc(sizeof(char)*(len/2));
                            read(fd1[0], lstring, len);
                            printf("Child Left: %s\n", lstring);
                            close(fd1);
                            //execl("child.c", parent);
                            status = 0;
                            }
                    }
    }
}

else{       //parent process
    //fork a second child process
    pid_t kid2 = fork();

    if (kid2 == 0) {    //second child process
        int status = 1;
        while(status){
            int retval = select(fd2[0]+1, &read_set, NULL, NULL, &tv);

            switch(retval) {
            case -1:
                    printf("Select Error.\n");
                    exit (-1);
                    status = 0;
                    break;

            case 0:
                    printf("Timeout...");
                    status = 0;
                    break;

            default:
                    if (FD_ISSET(fd2[0], &read_set)) {
                        char *rstring = malloc(sizeof(char)*((len/2)+(len%2)));
                        read(fd2[0], rstring, len);
                        printf("Child Right: %s\n", rstring);
                            //execl("child.c", parent);
                        status = 0;
                    }
            }
    }
    }

    else{
        int status;
        //create character arrays for
        printf("\n\nParent Original String: %s\n", passed);
        printf("Measured Length: %d\n", len);
        int left = (len/2);
        int right =(len/2)+(len % 2);
        char *lstring = malloc(sizeof(char)*(left+1));
        char *rstring = malloc(sizeof(char)*(right+1));
        memcpy(lstring, passed, left);
        lstring[left] = '\0';
        memcpy(rstring, passed+left, right);
        rstring[right] = '\0';
        printf("Parent Left: %s\n", lstring);
        printf("Parent Right: %s\n", rstring);
        write(fd1[1], lstring, sizeof(char)*(left+1));
        write(fd2[1], rstring, sizeof(char)*(right+1));
        waitpid(kid, &status, NULL);
        waitpid(kid2, &status, NULL);
        }
    return 0;
}
return 0;
}

附注:不要将fd1fd2初始化为有效的文件描述符号。我总是将它们初始化为“-1”。 - Jonathon Reinhart
1个回答

5

如果您阅读参考页面,您将会看到:

成功完成后,pselect()或select()函数将修改readfds、writefds和errorfds参数所指向的对象。

因此,在调用select之前,您必须在每次循环迭代中设置描述符集。

还要注意,超时结构体也可能被修改。

您还应该将最大描述符(加一)作为第一个参数。如果fd2[0]大于fd1[0],则调用将无法按预期工作。


谢谢。这让我很有感触。我确实尝试阅读了手册,但它们写得非常密集,以至于我通常感觉除非我已经知道我在寻找什么答案,否则我无法找到答案。我感激你用简单的英语解释清楚了它。 - ReezaCoriza
仍然有效...谢谢 - maxkoryukov

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接