如何在 Windows 上的 select() 中取消等待
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3333361/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to cancel waiting in select() on Windows
提问by Artyom
In my program there is one thread (receiving thread) that is responsible for receiving requests from a TCP socket and there are many threads (worker threads) that are responsible for processing the received requests. Once a request is processed I need to send an answer over TCP.
在我的程序中,有一个线程(接收线程)负责从 TCP 套接字接收请求,还有许多线程(工作线程)负责处理接收到的请求。处理请求后,我需要通过 TCP 发送答案。
And here is a question. I would like to send TCP data in the same thread that I use for receiving data. This thread after receiving data usually waits for new data in select()
. So once a worker thread finished processing a request and put an answer in the output queue it has to signal the receiving thread that there are data to send. The problem is that I don't know how to cancel waiting in select()
in order to get out of waiting and to call send()
.
这是一个问题。我想在用于接收数据的同一线程中发送 TCP 数据。该线程在接收到数据后通常会等待select()
. 因此,一旦工作线程完成处理请求并将答案放入输出队列,它必须通知接收线程有数据要发送。问题是我不知道如何取消等待select()
以摆脱等待并调用send()
.
Or shall I use another thread solely for sending data over TCP?
或者我应该使用另一个线程来单独通过 TCP 发送数据吗?
Updated
更新
MSalters, Artyom thank you for you answers!
MSalters,Artyom 感谢您的回答!
MSalters, having read your answer I found this site: Winsock 2 I/O Methodsand read about WSAWaitForMultipleEvents()
. My program in fact must work both on HP-UX and Windows I finally decided to use the approach that had been suggested by Artyom.
MSalters,在阅读了您的回答后,我找到了这个站点:Winsock 2 I/O Methods并阅读有关WSAWaitForMultipleEvents()
. 我的程序实际上必须同时在 HP-UX 和 Windows 上运行 我最终决定使用 Artyom 建议的方法。
回答by Artyom
You need to use something similar to safe-pipe trick, but in your case you need to use a pair of connected TCP sockets.
您需要使用类似于安全管道技巧的东西,但在您的情况下,您需要使用一对连接的 TCP 套接字。
- Create a pair of sockets.
- Add one to the select and wait on it as well
- Notify by writing to other socket from other threads.
- Select is immediately waken-up as one of the sockets is readable, reads all the data in this special socket and check all data in queues to send/recv
- 创建一对套接字。
- 将一个添加到选择中并等待它
- 通过从其他线程写入其他套接字来通知。
- Select 立即被唤醒,因为其中一个套接字是可读的,读取这个特殊套接字中的所有数据并检查队列中的所有数据以发送/接收
How to create pair of sockets under Windows?
如何在 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 some checks should be added for return values.
当然,应该为返回值添加一些检查。
回答by MSalters
select
is not the native API for Windows. The native way is WSAWaitForMultipleEvents. If you use this to create an alertable wait, you can use QueueUserAPCto instruct the waiting thread to send data. (This might also mean you don't have to implement your own output queue)
select
不是 Windows 的本机 API。本机方式是WSAWaitForMultipleEvents。如果您使用它来创建可警报的等待,您可以使用QueueUserAPC来指示等待线程发送数据。(这也可能意味着您不必实现自己的输出队列)
回答by guido4096
See also this post: How to signal select() to return immediately?
另请参阅这篇文章: 如何向 select() 发出信号以立即返回?
For unix, use an anonymous pipe. For Windows: Unblocking can be achieved by adding a dummy (unbound) datagram socket to fd_set and then closing it. To make this thread safe, use QueueUserAPC:
对于 unix,请使用匿名管道。对于 Windows:可以通过向 fd_set 添加一个虚拟(未绑定)数据报套接字然后关闭它来实现解除阻塞。要使此线程安全,请使用 QueueUserAPC:
The only way I found to make this multi-threadsafe is to close and recreate the socket in the same thread as the select statement is running. Of course this is difficult if the thread is blocking on the select. And then comes in the windows call QueueUserAPC. When windows is blocking in the select statement, the thread can handle Asynchronous Procedure Calls. You can schedule this from a different thread using QueueUserAPC. Windows interrupts the select, executes your function in the same thread, and continues with the select statement. You can now in your APC method close the socket and recreate it. Guaranteed thread safe and you will never loose a signal.
我发现使这个多线程安全的唯一方法是在运行 select 语句的同一线程中关闭并重新创建套接字。当然,如果线程在选择上阻塞,这很困难。然后在windows 中调用QueueUserAPC。当 windows 在 select 语句中阻塞时,线程可以处理异步过程调用。您可以使用 QueueUserAPC 从不同的线程进行调度。Windows 中断选择,在同一线程中执行您的函数,然后继续选择语句。您现在可以在 APC 方法中关闭套接字并重新创建它。保证线程安全,您永远不会丢失信号。
回答by sarnold
The typical model is for the worker to handle its own writing. Is there a reason why you want to send all the output-IO through select
ing thread?
典型的模型是让工人处理自己的写作。有什么理由要通过select
ing线程发送所有输出IO吗?
If you're sure of this model, you could have your workers send data back to the master thread using file descriptors as well (pipe(2)
) and simply add those descriptors to your select()
call.
如果您确定这个模型,您可以让您的工作人员也使用文件描述符 ( pipe(2)
)将数据发送回主线程,然后只需将这些描述符添加到您的select()
调用中。
And, if you're especially sure that you're not going to use pipes to send data back to your master process, the select
call allows you to specify a timeout. You can busy-wait while checking your worker threads, and periodically call select
to figure out which TCP sockets to read from.
而且,如果您特别确定不会使用管道将数据发送回主进程,则该select
调用允许您指定超时。您可以在检查工作线程时忙等待,并定期调用select
以确定要读取的 TCP 套接字。
回答by MSalters
Another quick&dirty solution is to add localhost sockets to the set. Now use those sockets as the inter-thread communication queues. Each worker thread simply sends something to its socket, which ends up on the corresponding socket in your receiving thread. This wakes up the select()
, and your receiving thread can then echo the message on the appropriate outgoing socket.
另一个快速而肮脏的解决方案是将本地主机套接字添加到集合中。现在使用这些套接字作为线程间通信队列。每个工作线程只是简单地向它的套接字发送一些东西,它在你的接收线程中的相应套接字上结束。这会唤醒select()
,然后您的接收线程可以在适当的传出套接字上回显消息。