我有一个工作线程正在侦听 TCP 套接字以获取传入流量,并缓冲接收到的数据以供主线程访问(我们称之为套接字A)。但是,即使没有数据进来,工作线程也必须执行一些常规操作(例如每秒一次)。因此,我使用select()
超时,这样我就不需要继续轮询。(请注意,调用receive()
非阻塞套接字然后休眠一秒钟是不好的:传入的数据应该立即可供主线程使用,即使主线程可能并不总是能够立即处理它,因此需要缓冲。)
现在,我还需要能够立即向工作线程发出信号以执行其他操作;从主线程开始,我需要立即让工作线程select()
返回。目前,我已经解决了这个问题(基本上是从这里和这里采用的方法):
在程序启动时,工作线程为此目的创建一个额外的数据报 (UDP) 类型的套接字,并将其绑定到某个随机端口(我们称之为套接字B)。同样,主线程创建一个用于发送的数据报套接字。在对 的调用中,工作线程select()
现在在. 当主线程需要发出信号时,它会发送几个字节到相应的端口 on 。回到工作线程,如果B保留在after返回中,则调用 then 并简单地忽略接收到的字节。fd_set
sendto()
localhost
fd_set
select()
recvfrom()
这似乎工作得很好,但我不能说我喜欢这个解决方案,主要是因为它需要为B绑定一个额外的端口,而且还因为它添加了几个额外的套接字 API 调用,我猜这些调用可能会失败——我不真的很想为每个案例找出适当的行动。
我认为理想情况下,我想调用一些以Aselect()
作为输入的函数,除了立即返回之外什么都不做。但是,我不知道这样的功能。(我想我可以例如shutdown()
套接字,但副作用是不能接受的:)
如果这是不可能的,那么第二好的选择是创建一个比真正的 UDP 套接字更笨的B,并且实际上不需要分配任何有限的资源(超出合理的内存量)。我猜Unix 域套接字可以做到这一点,但是:该解决方案的跨平台性不应该比我目前拥有的少得多,尽管一些适量的#ifdef
东西是可以的。(我主要针对 Windows 和 Linux ——顺便写一下 C++。)
请不要建议重构以摆脱两个单独的线程。这种设计是必要的,因为主线程可能会被阻塞很长时间(例如,做一些密集的计算——我不能receive()
从最里面的计算循环开始定期调用),同时,有人需要缓冲传入的数据(并且由于我无法控制的原因,它不能是发件人)。
现在我正在写这篇文章,我意识到肯定有人会简单地回复“ Boost.Asio ”,所以我只是第一次看它......虽然找不到明显的解决方案。请注意,我也不能(轻松)影响套接字A的创建方式,但如果需要,我应该能够让其他对象包装它。