我有一个工作线程正在侦听 TCP 套接字以获取传入流量,并缓冲接收到的数据以供主线程访问(我们将此套接字称为A)。但是,即使没有数据传入,工作线程也必须执行一些常规操作(例如每秒一次)。因此,我使用select()
超时,这样我就不需要继续轮询。 (请注意,调用receive()
在非阻塞套接字上然后休眠一秒钟并不好:传入的数据应该立即可供主线程使用,即使主线程可能并不总是能够立即处理它,因此需要缓冲。 )
现在,我还需要能够向工作线程发出信号以立即执行其他操作;从主线程,我需要使工作线程select()
立即返回。目前,我已经解决了这个问题如下(方法基本上采用自here http://mail.python.org/pipermail/python-list/2002-May/147063.html and here http://www.developerweb.net/forum/showthread.php?t=5154):
在程序启动时,工作线程为此目的创建一个数据报(UDP)类型的附加套接字,并将其绑定到某个随机端口(我们称此套接字为B)。同样,主线程创建一个用于发送的数据报套接字。在其呼吁中select()
,工作线程现在列出了两者A and B in the fd_set
。当主线程需要发出信号时,sendto()
是几个字节到相应的端口localhost
。回到工作线程,如果B仍留在fd_set
after select()
返回,则recvfrom()
被调用并且接收到的字节被简单地忽略。
这似乎工作得很好,但我不能说我喜欢这个解决方案,主要是因为它需要绑定一个额外的端口B,而且还因为它添加了几个额外的套接字 API 调用,我猜这些调用可能会失败 - 而且我真的不想为每种情况找出适当的操作。
我认为理想情况下,我想调用一些需要的函数A作为输入,除了使select()
立即返回。但是,我不知道这样的功能。 (我想我可以例如shutdown()
套接字,但副作用是不能接受的:)
如果这是不可能的,第二个最佳选择是创建一个B它比真正的 UDP 套接字要虚拟得多,并且实际上不需要分配任何有限的资源(超出合理的内存量)。我猜Unix 域套接字 http://en.wikipedia.org/wiki/Unix_domain_sockets确实会这样做,但是:该解决方案的跨平台性不应比我目前拥有的少得多,尽管有一定数量的#ifdef
东西很好。 (我主要针对 Windows 和 Linux – 顺便编写 C++。)
请不要建议重构以消除两个单独的线程。这种设计是必要的,因为主线程可能会被阻塞很长一段时间(例如,进行一些密集的计算 - 并且我无法开始定期调用receive()
来自最内层的计算循环),同时,有人需要缓冲传入的数据(并且由于我无法控制的原因,它不能是发送者)。
现在写到这里,我发现肯定有人会简单地回复“Boost.Asio http://www.boost.org/doc/libs/1_37_0/doc/html/boost_asio.html“,所以我只是第一次看到它......不过,找不到明显的解决方案。请注意,我也不能(轻易)影响套接字的方式A已创建,但如果需要,我应该能够让其他对象包装它。