Understanding POSIX select () with read and write fd_set

advertisements

For a school project, we are to implement concurrency on one machine using file descriptors and 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. I can get stuff to happen with the write file descriptors, but the read fds seem to never be ready. Can I get some help understanding how select() works with read and write descriptors? 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().

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. 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_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...

}