I'm calling FD_SET() to set the write_fd of a non-blocking socket while select() is blocking within another thread – the problem is that select() keeps blocking even if the fd is ready to write.
What I actually want do is: Preparing data to write for this socket within another thread, afterwards I add the socket to the write_fd. The select() thread should recognise that and handle the prepared data.
Doesn't select() recognise changes within the fd while blocking? If yes – is there something like the epoll() EPOLL_CTL_MOD instead of FD_SET() to update the set; or is the only way to recognise changes to set the timeout of the select()-function?
In my opinion that wouldn't be a solution because that would be "slow" and would produce CPU overhead ...
EDIT:
// This thread is running all day long ...
static void * workman() {
FD_ZERO(&fd_read);
FD_ZERO(&fd_write);
FD_SET(socketId , &fd_read);
while(1) {
// PROBLEM Keeps blocking when box() is called
select(socketId+1, &fd_read, &fd_write, NULL, NULL);
if(FD_ISSET(socketId, &fd_read)) {
// RECIVE DATA
}
else if(FD_ISSET(socketId, &fd_write)) {
FD_CLR(socketId, &fd_write);
pthread_mutex_lock(&interface.mutex);
strncpy(conn.outBuffer, interface.buffer, strlen(interface.buffer));
interface.buffer[0] = '\0';
pthread_mutex_unlock(&interface.mutex);
// SEND DATA
}
}
return 0;
}
// This function is called within another thread on user input
int box(char *content) {
pthread_mutex_lock(&interface.mutex);
// preparing the data and write it into interface.buffer if available
pthread_mutex_unlock(&interface.mutex);
FD_SET(socketId, &fd_write);
return 0;
}
Yes, as you suspect, select()
will not detect changes done to the file descriptor sets from another thread. After all, it cannot do that efficiently, without some magic mechanism to asynchronously detect writes to specific memory locations.
And, yes, you should use the epoll
interface. The man page of epoll_wait
specifically notes that changes from another thread are handled.
While one thread is blocked in a call to epoll_pwait(), it is possible for another thread to add a file descriptor to the waited-upon epoll instance. If the new file descriptor becomes ready, it will cause the epoll_wait() call to unblock.
But, if you are unable to use epoll
or another file notification interface which supports such changes, there is still a solution. You can use an internal pipe
(or similar mechanisms such as eventfd
), to cause select
to return and restart after you have updated the file descriptor sets. Of course, you should be careful to do proper locking to avoid race conditions. Likewise, be sure to put the pipe into non-blocking mode, or a write
to the write end of the pipe could block under heavy load and possibly cause your program to deadlock.
In order to do something like that, select would need to be internally polling with the "current" fd set, which would really be a CPU overhead and you wouldn't be able to control the period of the polling. That's what select is for I think.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With