如何在 Windows 上取消 select() 中的等待
在我的程序中,有一个线程(接收线程)负责从 TCP 套接字接收请求,并且有许多线程(工作线程)负责处理接收到的请求。处理请求后,我需要通过 TCP 发送答案。
这是一个问题。我想在用于接收数据的同一个线程中发送 TCP 数据。该线程接收数据后通常会在select()
中等待新数据。因此,一旦工作线程处理完请求并将答案放入输出队列中,它就必须向接收线程发出信号,表明有数据要发送。问题是我不知道如何取消 select()
中的等待,以便摆脱等待并调用 send()
。
或者我应该使用另一个线程专门通过 TCP 发送数据吗?
已更新
MSalters、Artyom 感谢您的回答!
MSalters,读完你的答案后,我找到了这个网站: Winsock 2 I/O 方法 并阅读关于WSAWaitForMultipleEvents()
。事实上,我的程序必须同时在 HP-UX 和 Windows 上运行,我最终决定使用 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.
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()
.
Or shall I use another thread solely for sending data over TCP?
Updated
MSalters, Artyom thank you for you answers!
MSalters, having read your answer I found this site: Winsock 2 I/O Methods and 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.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
您需要使用类似于安全管道技巧的东西,但在您的情况下,您需要使用一对连接的 TCP 套接字。
这个特殊套接字中的数据并检查队列中的所有数据以发送/接收
如何在Windows下创建套接字对?
当然应该为返回值添加一些检查。
You need to use something similar to safe-pipe trick, but in your case you need to use a pair of connected TCP sockets.
data in this special socket and check all data in queues to send/recv
How to create pair of sockets under Windows?
Of course some checks should be added for return values.
select
不是 Windows 的本机 API。本机方式是 WSAWaitForMultipleEvents。如果您使用它来创建可警报的等待,则可以使用 QueueUserAPC 来指示等待线程发送数据。 (这也可能意味着您不必实现自己的输出队列)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 QueueUserAPC to instruct the waiting thread to send data. (This might also mean you don't have to implement your own output queue)另请参阅这篇文章:
如何通知 select() 立即返回?
对于 unix,请使用匿名管道。对于 Windows:
解除阻塞可以通过向 fd_set 添加一个虚拟(未绑定)数据报套接字然后关闭它来实现。为了使这个线程安全,请使用 QueueUserAPC:
我发现使这个多线程安全的唯一方法是在运行 select 语句的同一线程中关闭并重新创建套接字。当然,如果线程在选择上阻塞,这会很困难。然后在windows进来调用QueueUserAPC。当 windows 在 select 语句中阻塞时,线程可以处理异步过程调用。您可以使用 QueueUserAPC 从不同的线程安排此操作。 Windows 中断 select,在同一线程中执行您的函数,然后继续执行 select 语句。您现在可以在 APC 方法中关闭套接字并重新创建它。保证线程安全,您永远不会丢失信号。
See also this post:
How to signal select() to return immediately?
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:
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 线程发送所有输出 IO?
如果您确定此模型,您可以让工作人员也使用文件描述符 (
pipe(2)
) 将数据发送回主线程,然后只需将这些描述符添加到您的select 中()
调用。而且,如果您特别确定不会使用管道将数据发送回主进程,则
select
调用允许您指定超时。您可以在检查工作线程时处于忙等待状态,并定期调用select
来确定要读取哪些 TCP 套接字。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?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 yourselect()
call.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 callselect
to figure out which TCP sockets to read from.另一个快速而肮脏的解决方案是将本地主机套接字添加到集合中。现在使用这些套接字作为线程间通信队列。每个工作线程只需向其套接字发送一些内容,该内容最终会到达接收线程中相应的套接字。这会唤醒
select()
,然后您的接收线程可以在适当的传出套接字上回显该消息。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.