【问题标题】:Waiting for multiple events without polling等待多个事件而不进行轮询
【发布时间】:2013-08-11 13:21:42
【问题描述】:

我是 linux 编程新手,对所有的同步工具并不完全熟悉,所以我想请教更多知识渊博的人,他们如何解决这个问题。

我有一个线程,我想通过一个循环运行。循环中的停止点将是对套接字的读取操作。我希望读取操作阻塞一段时间然后超时。但是,如果某些事件需要注意,我需要一种方法来解除读取线程的阻塞。 “事件”可以是多种不同事物中的任何一种,因此我需要某种方式来告诉线程是什么导致读取解除阻塞。

我知道您可以使用信号解除阻止的读取,但我不确定这是如何完成的。

【问题讨论】:

  • 为什么不让一个线程只处理阻塞读取,而另一个线程做任何其他打断你的事情?看起来你想要一个线程架构并避免轮询,然后你问如何使用另一个范式多路复用其他工作。
  • 这是一个 XY 问题:OP 的印象是,如果线程 Y 卡在阻塞读取上,则线程 X 无法写入套接字:)

标签: c linux


【解决方案1】:

查看select() 系统调用。

这对于等待多个文件通道特别有用。

【讨论】:

  • 我不是在等待多个文件通道。只有一个插座。其他事件可能需要注意,所以我必须解除对读取的阻塞,让线程关闭并处理需要注意的任何事情。
  • @user1143970:根据其他事件的性质,也许它们可以提供 i/o 准备作为同步机制。 select() 是一个非常成熟的机制。否则,看起来多线程甚至多进程可能更合适。
【解决方案2】:

epoll 似乎是要走的路:

epoll API 执行与 poll(2) 类似的任务:监控多个 文件描述符以查看是否可以在其中任何一个上进行 I/O。 epoll API 可以用作边沿触发或电平触发的接口。 face 并且可以很好地扩展到大量监视的文件描述符。这 提供以下系统调用来创建和管理 epoll 实例:

man epoll 了解更多信息。您可能希望查看手册中的“建议使用示例”部分。

另见epoll vs select

【讨论】:

  • 这里有一个场景:我阻塞了一个套接字读取操作并且队列中出现了一条消息。队列是指由我的程序维护的队列。我需要线程解除阻塞,获取消息,通过套接字发送,然后返回读取。如果我的线程在读取时被阻塞,我如何解除阻塞并告诉它检查队列?
  • @user1143970 不确定我是否理解正确。让我们看看:你的线程应该从两个不同的地方读取,一个队列和一个 socked。如果两者都是文件描述符,您可以使用 epoll 读取这两个描述符,并且第一个准备好让您的线程使用的描述符,它将获取并工作。这是正确的/可能的吗?
  • 您的留言是什么?它们可以由其他线程处理还是必须中断您的阅读?如果你必须中断你的阅读,你必须以某种方式“轮询”,轮询、选择、epoll 或使用信号(异步,这更棘手)
  • @user1143970 - 只需从写入线程通过套接字发送消息。 IP 堆栈可以在同一个套接字上进行一个线程读取和另一个写入。
【解决方案3】:

您可以设置套接字操作的超时时间。示例:

struct timeval timeout;    
timeout.tv_sec = TIMEOUT_SEC;
timeout.tv_usec = TIMEOUT_MSEC;

setsockopt(sock_fd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));

/* now receive msg */
recvmsg(sock_fd, &msg, 0);

当你想让你的套接字阻塞时,这样做:

timeout.tv_sec = 0;
timeout.tv_usec = 0;
setsockopt(sock_fd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));

【讨论】:

    【解决方案4】:

    听起来像其他人提到的那样,您想使用select(),但您还想要一种在某种“消息”可用时中断它的方法。中断select() 的典型方法是使用self pipe trick。基本上,您在管道的读取文件描述符上创建pipe()select()。当消息到达程序维护的队列时,将一个字节写入管道。这将导致您的选择调用返回,您将能够检查您的管道是否已准备好读取。如果是,那么您知道您有一条消息要处理(无论您的上下文中是什么),所以您处理它,然后返回到select()。更好的是,您可以让您的管道实际上是您的消息队列。如果您只是使用管道作为表示消息在您的队列中的一种方式,请确保您实际上 read() 每次通过管道的字节数,否则它最终会填满并阻止您向它写入更多通知.

    尽管正如其他人所提到的,为什么不让一个线程为您的队列服务并写入套接字,而另一个线程进行读取?可能要简单得多。

    【讨论】:

    • 是否可以使用 pselect 并让另一个线程传递信号来中断 pselect?如果是这样,第二个线程会发送什么信号?
    【解决方案5】:

    也许这两个库对你有用:

    它们都在一个或多个线程上使用事件驱动范例(如果需要)。当然,您可以使用已经提到的 API 和条件变量来实现自己的事件驱动框架,但这可能比必要的工作量更大。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-05-08
      • 2020-08-31
      • 1970-01-01
      • 2011-07-21
      • 1970-01-01
      相关资源
      最近更新 更多