代码之家  ›  专栏  ›  技术社区  ›  Reunanen

如何发出select()立即返回的信号?

  •  25
  • Reunanen  · 技术社区  · 17 年前

    A. )但是,即使没有数据输入,工作线程也必须执行一些常规操作(例如,每秒一次)。因此,我使用 select() receive() 在非阻塞套接字上,然后休眠一秒钟是不好的:传入的数据应该立即可用于主线程,即使主线程可能并不总是能够立即处理它,因此需要缓冲。)

    现在,我还需要能够向worker线程发出信号,立即执行其他一些操作;从主线程开始,我需要创建工作线程的 选择() here here

    在程序启动时,工作线程为此创建一个数据报(UDP)类型的附加套接字,并将其绑定到某个随机端口(我们称之为套接字) B 选择() ,此时工作线程将同时列出这两个线程 和 B 在 fd_set . 当主线程需要发送信号时,它 sendto() 上的相应端口有几个字节 localhost . 如果需要,返回工作线程 fd_集 之后 那就回来吧 recvfrom() 调用,接收的字节将被忽略。

    这似乎工作得很好,但我不能说我喜欢这个解决方案,主要是因为它需要为服务器绑定一个额外的端口 ,还因为它添加了几个额外的套接字API调用,可能会失败,我想,我真的不想为每种情况找出合适的操作。

    A. 作为输入,除了make之外什么都不做 选择() shutdown() 插座,但副作用实际上是不可接受的:)

    B 这比真正的UDP套接字要简单得多,并且实际上不需要分配任何有限的资源(超出合理的内存量)。我猜 Unix domain sockets 可以做到这一点,但是:解决方案的跨平台性不应该比我目前拥有的少很多,尽管有一些适度的 #ifdef 东西很好。(我主要针对Windows和Linux,并通过C++编写。)

    同时,有人需要缓冲传入的数据(由于我无法控制的原因,它不能是发送方)。

    现在我正在写这篇文章,我意识到肯定有人会简单地回答” Boost.Asio A. 是创建的,但我应该能够让其他对象包装它,如果必要的话。

    3 回复  |  直到 17 年前
        1
  •  36
  •   Alex B    17 年前

    你就快到了。使用 "self-pipe" trick . 打开一个管道,将其添加到 select() 读写 fd_set ,从主线程写入以取消阻止工作线程。它可以跨POSIX系统移植。

    我在一个系统中看到了类似Windows技术的变体(事实上与上面的方法一起使用,由 #ifdef WIN32 然后关闭它。当然,缺点是每次都必须重新打开它。

    选择() ,这取决于为工作线程安排的时间。

        2
  •  3
  •   MarkR    17 年前

    使用管道而不是插座有点干净,因为不可能有另一个过程抓住它,把事情搞砸。

    匿名管道将永远无法用于任何其他进程(除非您将其提供给它)。

    您也可以使用信号,但在多线程程序中,您需要确保除所需线程外的所有线程都屏蔽了该信号。

        3
  •  1
  •   guido4096    13 年前

    我找到的使这个多线程安全的唯一方法是在select语句运行时在同一线程中关闭并重新创建套接字。当然,如果线程在select上阻塞,这是很困难的。然后进入windows调用QueueUserAPC。当windows在select语句中阻塞时,线程可以处理异步过程调用。您可以使用QueueUserAPC从其他线程对此进行调度。Windows中断select,在同一线程中执行函数,然后继续执行select语句。现在,您可以在APC方法中关闭套接字并重新创建它。保证线程安全,永远不会丢失信号。

    推荐文章