【问题标题】:Linux: application responsiveness and select()Linux:应用程序响应和 select()
【发布时间】:2012-09-27 21:59:16
【问题描述】:

我有一个 C++ 控制台应用程序,它使用 open() [O_RDWR | O_NONBLOCK]write()select()read()close() 来处理设备文件。也可以调用ioctl() 来取消当前操作。在任何给定时间,只有一个用户可以使用设备。

我需要提出具有 libsigc++ 信号的 C++ 类,当设备提供数据时会触发这些信号。

问题:当调用select() 时,应用程序在等待数据时变得无响应。如何使其响应 - 通过在工作线程中调用 select()?如果是这样 - 工作线程将如何与主线程通信?也许我应该看看boost::asio

【问题讨论】:

  • 不想等待数据为什么还要调用select呢?如果您只想检查数据是否可用,请使用超时为零的 select(请参阅man select)。
  • @JonasWielicki 如何比等待特定时间量或无限期等待更好?如果超时为零,那么对 select() 的调用将在循环中执行,并且无论如何都会阻塞。还是我错过了什么?
  • 如果你不想等待,为什么还要经常调用 select?
  • @JonasWielicki 事先不知道数据何时可用,这就是应用程序等待的原因
  • 也许你必须重新考虑你的设计。要么您有工作要做,在这种情况下,您可以在 select 循环内完成工作,或者您不这样做,然后您不介意 select 是否进入睡眠状态。将 eventfd 添加到 fd 集可能是让您的“工作”确定何时需要再次唤醒它的好方法。

标签: c++ linux multithreading boost-asio boost-thread


【解决方案1】:

如何使其响应 - 通过在工作线程中调用 select()

您可以使用dup(),这将复制您的文件描述符...因此您可以将整个读取操作移至另一个线程。因此,即使读取 [select()] 线程处于休眠状态,您的写入线程和处理线程也会响应。

libsigc++ 的信号发射开销很小,因此我认为您可以在读取线程本身内嵌入代码。插槽可以存在于不同的线程中,这是您将接收信号的地方...

我认为 Thrift 源代码 [完全基于 boost] 可能会引起您的兴趣,尽管 thrift 不使用 libsigc++。

【讨论】:

    【解决方案2】:

    听起来好像您误解了选择; select(或 poll、epoll 等)的目的不是“等待数据”,而是“等待一系列文件描述符或计时器上发生一个或多个事件,或发出信号”。

    您在选择通话时缺少哪些“响应能力”?您说这是一个控制台应用程序,所以您不是在谈论 GUI 循环,所以大概它与 IO 相关?如果是这样,那么您需要重构您的选择,以便等待您正在谈论的数据是一个元素;也就是说,如果您使用 select,则构建您想要等待输入的所有文件/套接字描述符(以及 stdin 和 stdout 是文件描述符)的 FD_SET。

    或者构建一个循环,定期调用“select”,并在很短的时间内调用 /test/ 以获取任何待处理的输入,并且仅在 select 告诉您有要读取的内容时尝试读取它。

    【讨论】:

      【解决方案3】:

      听起来您有producer-consumer 样式问题。有多种方法可以解决这个问题,但现在大多数人倾向于使用基于condition variable 的方法(参见C++11 based example)。

      还有一些设计模式在实施时可以帮助缓解并发问题,例如:

      Half-Sync / Half-Async
      • 一种生产者-消费者样式模式,它在用事件填充队列的异步层和处理这些事件的同步层之间引入了一个队列。
      Leader / Followers
      • 多个线程轮流处理事件
      • 可以通过here进行相关讨论。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-11-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多