How to cancel wait in select () on Windows

In my program, there is one thread (the receiving thread) that is responsible for receiving requests from the TCP socket, and there are many threads (worker threads) that are responsible for processing received requests. After processing the request, I need to send a response over TCP.

And here is the question. I would like to send TCP data to the same stream that I use to receive data. After receiving this data, this stream usually expects new data in select() . Therefore, as soon as the worker thread completes the processing of the request and places the response in the output queue, it should signal to the receiving thread that there is data to send. The problem is that I do not know how to cancel the wait in select() in order to exit the wait and call send() .

Or use another thread exclusively to send data over TCP?

Update

MSalters, Artem thanks for the answers!

MSalters, after reading your answer, I found this site: Winsock 2 I / O Methods and read about WSAWaitForMultipleEvents() . My program should actually work both on HP-UX and Windows, I finally decided to use the approach proposed by Artem.

+6
c ++ multithreading windows sockets winsock
source share
5 answers

You need to use something similar to the safe-pipe trick, but in your case you need to use a couple of connected TCP sockets.

  • Create a pair of sockets.
  • Add it to your selection and wait too.
  • Notify by writing to another socket from other threads.
  • The choice immediately wakes up when one of the sockets is read, reads all the data in this special socket and check all the data in the queues to send / recv

How to create a pair of sockets under Windows?

 inline void pair(SOCKET fds[2]) { struct sockaddr_in inaddr; struct sockaddr addr; SOCKET lst=::socket(AF_INET, SOCK_STREAM,IPPROTO_TCP); memset(&inaddr, 0, sizeof(inaddr)); memset(&addr, 0, sizeof(addr)); inaddr.sin_family = AF_INET; inaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); inaddr.sin_port = 0; int yes=1; setsockopt(lst,SOL_SOCKET,SO_REUSEADDR,(char*)&yes,sizeof(yes)); bind(lst,(struct sockaddr *)&inaddr,sizeof(inaddr)); listen(lst,1); int len=sizeof(inaddr); getsockname(lst, &addr,&len); fds[0]=::socket(AF_INET, SOCK_STREAM,0); connect(fds[0],&addr,len); fds[1]=accept(lst,0,0); closesocket(lst); } 

Of course, for the return values ​​you need to add some checks.

+13
source share

select not a native API for Windows. Native WSAWaitForMultipleEvents path. If you use this to create the expected wait, you can use QueueUserAPC to instruct the waiting thread to send data. (This may also mean that you do not need to execute your own output queue)

+7
source share

See also this entry: How to correctly output select () for immediate return?

For unix, use the anonymous channel. For Windows: Unlocking can be achieved by adding a dummy (unconnected) datagram socket to fd_set and then closing it. To make this thread safe, use QueueUserAPC:

The only way I found to make this multi-threaded application is to close and recreate the socket in the same thread as the select statement. Of course, this is difficult if the thread blocks the selection. And then comes to Windows call QueueUserAPC. When windows are locked in a select statement, a thread can handle asynchronous procedure calls. You can schedule this from another thread using QueueUserAPC. Windows aborts the selection, executes your function in the same thread, and continues with the select statement. Now in your APC method you can close the socket and recreate it. Guaranteed thread safety and you will never lose a signal.

+4
source share

A typical model is designed for the employee to process his own letter. Is there a reason why you want to send all IO output through a select stream?

If you are confident in this model, you can send your employees back to the main stream using file descriptors ( pipe(2) ) and simply add these descriptors to the select() call.

And if you are especially sure that you are not going to use channels to send data back to your main process, the select call allows you to specify a timeout. You can revitalize by checking your workflows and periodically call select to find out which TCP sockets to read.

0
source share

Another quick and dirty solution is to add local hosts to the set. Now use these sockets as communication queues between threads. Each worker thread simply sends something to its socket, which ends on the corresponding socket in the receiving stream. This wakes up select() , and your receiving stream can then echo in the corresponding outgoing socket.

0
source share

All Articles