Interrupting select()
Hi all, I have nother question. I've decided to use multiple threads, each thread handling a set of clients. When I say "handling", I mean checking for read notification in a blocking select() call. Now, I need a way to interrupt select(), so I can signal my thread to terminate, or to rebuild the list of socket descriptors (if a new socket is added or one is removed). For my listening thread, I simply have another socket listening only on 127.0.0.1 on a specified port. When I need to interrupt the thread, I connect() to 127.0.0.1 on this port. The thread then sees that it's the notification socket, and it goes off to do whatever it needs to do. However, if I use this method for my new thread (for reading clinet data), there's two ways about it: 1) Have a socket in a listen state, and connect to it 2) Have a connected socket, and send data to it If I go for method 1, then I need to have a unique port for each thread (this might not be much of a problem though. Comments?). Method 2 seems even worse - I need to have a socket connected to some other internal socket (which uses up twice the number of socket descriptors, one for each end), but it means I only need to be listening on 1 port for however many threads I have. I presume that this is a fairly common problem, but I have no idea how to solve it. Any ideas? Cheers, Steve
I think I'll just go for method 1 just now. I don't expect to have more than 10 threads running anyway, so that's only 10 ports, which isn't too bad.
Still, it seems a bit... weird. Anyone have any ideas?
Still, it seems a bit... weird. Anyone have any ideas?
look into the pthread_cancel function, I think that will help you out.
Related to that, look into pthread_setcancelstate and pthread_setcanceltype
Related to that, look into pthread_setcancelstate and pthread_setcanceltype
Thanks for the reply. Unfortunately I'm using Windows' thread functions (CreateThread()). Also, I don't just want to stop the thread, I need to interrupt it.
For example, if I have a thread with 4 sockets in it, and another user connects, I need to add the new socket to this thread. However, The thread is processing a blocking select() call, and so it won't see that the socket list has been updated until it finishes the select() and re-fills the fd_set. If the current 4 sockets are fairly inactive (or totally inactive), then the select() call will take a long time to complete, and it'll therefore take a long time for the fd_set to be rebuilt with the new socket added. The end result is that the new connection doesn't get any recv() calls processed.
Using one listening socket in the fd_set seems to be working well, but I'd still be interested in hearing how others get around this problem.
For example, if I have a thread with 4 sockets in it, and another user connects, I need to add the new socket to this thread. However, The thread is processing a blocking select() call, and so it won't see that the socket list has been updated until it finishes the select() and re-fills the fd_set. If the current 4 sockets are fairly inactive (or totally inactive), then the select() call will take a long time to complete, and it'll therefore take a long time for the fd_set to be rebuilt with the new socket added. The end result is that the new connection doesn't get any recv() calls processed.
Using one listening socket in the fd_set seems to be working well, but I'd still be interested in hearing how others get around this problem.
How would the user connect without the select() un-blocking? Typically, the listening socket would be part of the select(). Are you doing select() in more than one thread?
Under UNIX, you can send a signal to a thread (or the entire process) which will unblock select(). Windows isn't quite as flexible about it, so using the wake-up method is reasonable. Another alternative is to select() with a time-out of, say, 100 milliseconds, and poll for updates and go right back to select()-ing.
Under UNIX, you can send a signal to a thread (or the entire process) which will unblock select(). Windows isn't quite as flexible about it, so using the wake-up method is reasonable. Another alternative is to select() with a time-out of, say, 100 milliseconds, and poll for updates and go right back to select()-ing.
enum Bool { True, False, FileNotFound };
I have 2 threads - One is accept()ing connections, and one is calling select()ing to call recv(). When a client connects, the accept()ing thread gets interrupted, the new client socket is created, and I add it to my list of sockets to read from. It's at this point that I need to interrupt the thread that's select()ing to call recv(), so I can refresh the fd_set to include the newly added socket.
I suppose I could combine both into one thread, but it makes my design cleaner this way (I have a CSocketServer and a CSocketSet class).
I suppose I could combine both into one thread, but it makes my design cleaner this way (I have a CSocketServer and a CSocketSet class).
Ok, that make sense. I'm not that great in the Windows programming area (as you can tell). Most of the threaded network applications I have seen tend to actually create a thread for each connection made, instead of having one thread go through a list. No idea on how to do it with how you have it structured.
Quick question though, why did you chose the penguin for your thread/post icon, it kinda through me off, as thats why I though you were doing this in Linux.
Quick question though, why did you chose the penguin for your thread/post icon, it kinda through me off, as thats why I though you were doing this in Linux.
On Unix you would create a pipe and stick the read part of the file descriptor pair in the list for select(). Stopping involves writing 4 bytes into the pipe (just any 'long' value would do). Unfortunately Windows' select() implementation cannot deal with multiple file descriptor types in this manner and you will need to use a WSA event for this. It goes like this (very simplified):
HANDLE l_hEvents[ 2 ];
HANDLE g_hServerStopEvent;
g_hServerStopEvent = ::CreateEvent( NULL, TRUE, FALSE, NULL );
l_hEvents[0] = ::WSACreateEvent();
l_hEvents[1] = g_hServerStopEvent;
//---- This hooks the WSA event to your socket
::WSAEventSelect( hSocket, l_hEvents[0], FD_READ );
for(;;)
{
DWORD l_dwWait = ::WSAWaitForMultipleEvents( 2, l_hEvents, FALSE, INFINITE, FALSE );
if ( l_dwWait == WSA_WAIT_EVENT_0)
{
//---- READ event
}
else if ( l_dwWait == WSA_WAIT_EVENT_0 + 1)
{
//---- STOP event
}
else
{
//---- Doh! Errrrrrr...
}
}
You break the WaitFor...() with the call ::SetEvent( g_hServerStopEvent );
-cb
HANDLE l_hEvents[ 2 ];
HANDLE g_hServerStopEvent;
g_hServerStopEvent = ::CreateEvent( NULL, TRUE, FALSE, NULL );
l_hEvents[0] = ::WSACreateEvent();
l_hEvents[1] = g_hServerStopEvent;
//---- This hooks the WSA event to your socket
::WSAEventSelect( hSocket, l_hEvents[0], FD_READ );
for(;;)
{
DWORD l_dwWait = ::WSAWaitForMultipleEvents( 2, l_hEvents, FALSE, INFINITE, FALSE );
if ( l_dwWait == WSA_WAIT_EVENT_0)
{
//---- READ event
}
else if ( l_dwWait == WSA_WAIT_EVENT_0 + 1)
{
//---- STOP event
}
else
{
//---- Doh! Errrrrrr...
}
}
You break the WaitFor...() with the call ::SetEvent( g_hServerStopEvent );
-cb
Quote:Ah, it's my default post icon (It's also the icon I drew and submitted ;))
Original post by Xipher
Quick question though, why did you chose the penguin for your thread/post icon, it kinda through me off, as thats why I though you were doing this in Linux.
I've changed my code to just select() for 250ms, since I was having issues before, and it should be more efficient liek this. A delay of 250ms to a new connection is nothing (Only the connecting client gets the delay), and 250ms is nothing to work about when shutting down the server also.
Thanks for all tge replies.
This topic is closed to new replies.
Advertisement
Popular Topics
Advertisement
Recommended Tutorials
Advertisement