Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

`select` on same fd from multiple threads

What will happen if I call select on the same open file descriptor from multiple threads?

Is this documented somewhere?

like image 912
Andrew Tomazos Avatar asked Dec 15 '22 20:12

Andrew Tomazos


2 Answers

According to the POSIX 2008 select specification, there is nothing that prohibits two threads from both calling select at the same time.

It is reasonable to infer that if both threads are monitoring overlapping sets of file descriptors and some of the common file descriptors become readable or writable or have errors diagnosed, then both threads may end up with a report that the common file descriptors are ready. This cannot be guaranteed; there are timing issues to worry about, and it may depend on scheduling of the threads, etc. It also means one of the threads may end up not finding data to read on a file descriptor that it was told contained data to read, precisely because the other thread got there first. Any given byte of data will be read by just one of the threads.

like image 108
Jonathan Leffler Avatar answered Jan 03 '23 07:01

Jonathan Leffler


According to the Linux manual page, select is a thread safe function and a cancellation point.

On Linux some operating systems, one thread will successfully enter select, while the other threads would be blocked (the body of select is a critical section). Whatever descriptors are returned to the first thread, then the second thread that successfully enters select would probably wake up immediately with the same set, since select is a level-triggered interface.

Thus, you can't use select to select on multiple sets of file descriptors simultaneously on Linux those operating systems.

Linux seems to support fully re-entrant execution, demonstrated with this test program:

void * reader (void *arg) {
    int *fds = (int *)arg;
    struct timeval to = { 2, 0 };
    fd_set rfds;

    FD_ZERO(&rfds);
    FD_SET(fds[0], &rfds);

    select(fds[0]+1, &rfds, 0, 0, &to);
}

int main () {
    int sp[2];
    pthread_t t[2];
    socketpair(AF_UNIX, SOCK_STREAM, 0, sp);
    pthread_create(&t[0], 0, reader, sp);
    pthread_create(&t[1], 0, reader, sp);
    pthread_join(t[0], 0);
    pthread_join(t[1], 0);
    return 0;
}

When timing this program on Linux (mine was 2.6.43), the program returned after 2 seconds, indicating both threads entered select concurrently.

like image 23
jxh Avatar answered Jan 03 '23 05:01

jxh