select is a demultiplexing mechanism. Although you use it to determine when data is ready for a single socket or timeout, it was actually intended to return data ready status on many sockets (hence fd_set ). In theory, this is the same with poll , epoll and kqueue . Combined with non-blocking I / O, these mechanisms provide the application writer with tools for implementing a single-threaded parallel server.
In my opinion, your application does not need such power. Your application will only handle two connections, and you are already using one thread for each connection. I believe that leaving the socket in I / O lock mode is more appropriate.
If you insist on non-blocking mode, my suggestion is to replace the select call with something else. Since what you want from select is an indicator of read or timeout readiness for a single socket, you can achieve a similar effect with recv passed with the appropriate parameters and with the corresponding timeout set in the socket.
tm.tv_sec = time; tm.tv_usec = 0; setsockopt(connectedSocket, SOL_SOCKET, SO_RCVTIMEO, (char *)&tm, sizeof(tm)); char c; swtich (recv(connectedSocket, &c, 1, MSG_PEEK|MSG_WAITALL)) { case -1: if (errno == EAGAIN) { // handle timeout ... } else { // handle other error ... } break; case 0: // FALLTHROUGH default: // handle read ready ... break; }
From man recv :
MSG_PEEK - this flag causes the receive operation to return data from the beginning of the receive queue without removing this data from the queue. Thus, a subsequent receive call will return the same data.
MSG_WAITALL (since Linux 2.2). This flag requests that the work block be executed before the full request. However, the call may still return less data than requested if the signal is caught, an error or shutdown occurs, or the next data to be received is of a different type than the one returned.
As for why select behaves the way you noticed. Although the select call is thread safe, it is probably completely protected from reinstallation. Thus, one call to the select stream will be enabled only after the completion of another call to the stream ( select calls will be serialized). It is built into the demultiplexer function. Its purpose is to serve as the sole arbiter for whom the connections are ready. So he wants to control one thread.