简体   繁体   English

通过读写fd_set了解POSIX select()

[英]Understanding POSIX select() with read and write fd_set

For a school project, we are to implement concurrency on one machine using file descriptors and select(). 对于学校项目,我们将使用文件描述符和select()在一台计算机上实现并发。 In the program, we have RequestChannel objects which contain two file descriptors, one for reading and one for writing, which are used to communicate to a separate process which was forked off at the beginning of execution. 在程序中,我们有RequestChannel对象,其中包含两个文件描述符,一个用于读取,一个用于写入,用于与执行开始时分叉的单独进程进行通信。 I can get stuff to happen with the write file descriptors, but the read fds seem to never be ready. 使用写文件描述符可以使事情发生,但是读fds似乎从未准备就绪。 Can I get some help understanding how select() works with read and write descriptors? 我可以得到一些帮助,以了解select()如何与读写描述符一起工作吗? Everything I see is dealing with sockets, which are just confusing me at this point, I just want to know about general file descriptors and select(). 我看到的所有内容都与套接字有关,这只是让我感到困惑,我只想了解通用文件描述符和select()。

Here is my select loop: 这是我的选择循环:

fd_set readset, writeset;
FD_ZERO(&readset); 
FD_SET(JohnDoe.read_fd(), &readset);
FD_SET(JoeSmith.read_fd(), &readset);
FD_SET(JaneSmith.read_fd(), &readset);
FD_ZERO(&writeset);
FD_SET(JohnDoe.write_fd(), &writeset);
FD_SET(JoeSmith.write_fd(), &writeset);
FD_SET(JaneSmith.write_fd(), &writeset);

int maxfd = 0;
maxfd = max(maxfd, JohnDoe.read_fd());
maxfd = max(maxfd, JohnDoe.write_fd());
maxfd = max(maxfd, JoeSmith.read_fd());
maxfd = max(maxfd, JoeSmith.write_fd());
maxfd = max(maxfd, JaneSmith.read_fd());
maxfd = max(maxfd, JaneSmith.write_fd());

int numready;
int count = 0;
while (count < 10) {
    numready = select(maxfd + 1, &readset, &writeset, NULL, NULL);
    if (numready == -1) {
        cout << "Fatal error, aborting\n";
        break; 
    }
    else { 
        if(FD_ISSET(JohnDoe.write_fd(), &writeset)) { //write_fd() returns write file descriptor
            JohnDoe.cwrite("data John Doe"); //one RequestChannel object
        }
        if(FD_ISSET(JoeSmith.write_fd(), &writeset)) {
            JoeSmith.cwrite("data Joe Smith");
        }
        if(FD_ISSET(JaneSmith.write_fd(), &writeset)) {
            JaneSmith.cwrite("data JaneSmith");
        }



        if(FD_ISSET(JohnDoe.read_fd(), &readset)) { 
            string s = JohnDoe.cread();
            cout << "John Doe cread: " << s << "\n";
        }
        if(FD_ISSET(JoeSmith.read_fd(), &readset)) { 
            string s = JoeSmith.cread();
            cout << "Joe Smith cread: " << s << "\n";
        }
        if(FD_ISSET(JaneSmith.read_fd(), &readset)) { 
            string s = JaneSmith.cread();
            cout << "Jane Smith cread: " << s << "\n";
        }
    }
}

You need to reinitialize the descriptor sets before each call to select() becuase select() modifies the descriptor sets. 在每次调用select()之前,您都需要重新初始化描述符集,因为select()会修改描述符集。 You can do this either by using FD_ZERO() / FD_SET() inside the loop or by initializing 'prototype' sets that you copy over the ones passed to select() : 您可以通过在循环内使用FD_ZERO() / FD_SET()或通过初始化传递给select()复制的“原型”集来实现此目的:

fd_set readset, writeset;

int maxfd = 0;
maxfd = max(maxfd, JohnDoe.read_fd());
maxfd = max(maxfd, JohnDoe.write_fd());
maxfd = max(maxfd, JoeSmith.read_fd());
maxfd = max(maxfd, JoeSmith.write_fd());
maxfd = max(maxfd, JaneSmith.read_fd());
maxfd = max(maxfd, JaneSmith.write_fd());

int numready;
int count = 0;
while (count < 10) {
    FD_ZERO(&readset); 
    FD_SET(JohnDoe.read_fd(), &readset);
    FD_SET(JoeSmith.read_fd(), &readset);
    FD_SET(JaneSmith.read_fd(), &readset);
    FD_ZERO(&writeset);
    FD_SET(JohnDoe.write_fd(), &writeset);
    FD_SET(JoeSmith.write_fd(), &writeset);
    FD_SET(JaneSmith.write_fd(), &writeset);

    numready = select(maxfd + 1, &readset, &writeset, NULL, NULL);

    // etc...

}

Yes cjbrooks12 is correct. 是的,cjbrooks12是正确的。 It is necessary to reset the fd_set between select() system calls. 必须在select()系统调用之间reset the fd_set

They act as input/output parameters; 它们充当输入/输出参数; they are read by and modified by the system call. 它们由系统调用读取和修改。 When select() returns, the values have all been modified to reflect the set of file descriptors ready . 当select()返回时,所有值都已修改to reflect the set of file descriptors ready So, every time before you call select(), you have to (re)initialize the fd_set values. 因此,每次调用select()之前,都to (re)initialize the fd_set值。

And also make while loop infinite (or increase counter value) so that it will wait until read fds become ready. 并且还要使while循环无限(或增加计数器值),以便它将等待直到读取fds准备就绪。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM