i came across this problem when writing my first async server with single select call:
if( (retv = select((hsock<highestsocket?highestsocket:hsock)+1, &rFdx, &wFdx, &eFdx, 0) ) > 0)
{
printf("select() ended...\n");
if(FD_ISSET(hsock, &rFdx))
{
// .... handle new connection
}
for(unsigned int i=0; i < ClientList.size(); i++)
{
ServerClient* client = ClientList[i];
if(FD_ISSET(client->socket, &rFdx))
{
// handle client read
}
if(FD_ISSET(client->socket, &wFdx))
{
// handle client write
}
}
}
I expect to select to stop waiting and then handle client write when calling FD_SET from other thread.
If i call FD_SET on client socket from same thread, everything works as expected. However calling it from other thread does nothing, select keeps waiting until any data is received from client.
Of course you can't modify data in one thread and expect that modification to be visible in other threads without the proper synchronization. It's likely that select
reads the fd_set
immediately when it's called and then never looks at it again; but regardless, there's no way of obtaining the necessary synchronization if select
has already been called. You really need to rethink your design. One solution would be the "self-pipe" trick: having a pipe open that select
is always looking for input on, and having your other threads send a message over the pipe to cancel any pending select
and get the select
thread to rescan the table of file descriptors it should be looking at (with the proper synchronization!) and update its own fd_set
s.