Question

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";
        }
    }
}
Was it helpful?

Solution

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

}

OTHER TIPS

Yes cjbrooks12 is correct. It is necessary to reset the fd_set between select() system calls.

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. So, every time before you call select(), you have to (re)initialize the fd_set values.

And also make while loop infinite (or increase counter value) so that it will wait until read fds become ready.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top