3

所以,情况是这样的。我有一个 C++ 库,它正在做一些进程间通信,它有一个wait()阻塞和等待传入消息的函数。困难在于我需要一个定时等待,如果在指定的时间内没有收到任何消息,它将返回一个状态值。

最优雅的解决方案可能是重写库以向其 API 添加定时等待,但为了这个问题,我假设它不可行。(实际上,它看起来很困难,所以我想知道另一个选项是什么。)

以下是我如何在繁忙的等待循环中使用伪代码执行此操作:

while(message == false && current_time - start_time < timeout)
{
  if (Listener.new_message()) then message = true;
}

不过,我不想要占用处理器周期的繁忙等待。而且我也不想只是sleep()在循环中添加一个调用来避免处理器负载,因为这意味着响应速度较慢。我想要一些通过适当的块和中断来做到这一点的东西。如果更好的解决方案涉及线程(这似乎很可能),我们已经在使用boost::thread,所以我更喜欢使用它。

我发布这个问题是因为这似乎是一种具有明确“最佳实践”正确答案的情况,因为这是一种非常常见的模式。正确的方法是什么?

编辑补充:我在这里的很大一部分担心是,这是程序中的一个点,它既对性能至关重要,又对避免竞争条件或内存泄漏至关重要。因此,虽然“使用两个线程和一个计时器”是有用的建议,但我仍然试图弄清楚如何以安全和正确的方式实际实现它,而且我很容易看到自己在我的代码中犯了新手错误甚至不知道我做了。因此,一些实际的示例代码将不胜感激!

另外,我担心多线程解决方案:如果我使用“将阻塞调用放在第二个线程中并在该线程上执行定时等待”方法,如果阻塞调用永远不会返回,那么第二个线程会发生什么? 我知道第一个线程中的定时等待会返回,我会看到没有任何答案发生并继续处理,但是我是否“泄漏”了一个将永远处于阻塞状态的线程?有没有办法避免这种情况?(有什么方法可以避免这种情况并避免泄漏第二个线程的内存?)如果阻塞调用没有返回,我需要一个完整的解决方案来避免泄漏。

4

6 回答 6

1

您想要的是select(2)之类的东西,具体取决于您所针对的操作系统。

于 2010-11-20T10:43:38.220 回答
1

听起来您需要一个“监视器”,能够通过共享互斥体(通常)向线程发送资源可用性信号。在 Boost.Thread 中,一个condition_variable可以完成这项工作。

于 2010-11-20T11:33:10.367 回答
1

您可能想查看定时锁:您的阻塞方法可以在开始等待之前获取锁,并在数据可用时立即释放它。然后,您可以尝试在定时等待方法中获取锁(超时)。

于 2010-11-20T11:42:27.557 回答
1

将阻塞调用封装在单独的线程中。在该线程中有一个由条件变量保护的中间消息缓冲区(如前所述)。使您的主线程定时等待该条件变量。如果满足条件,则接收中间存储的消息。

所以基本上在 API 和您的应用程序之间放置一个能够定时等待的新层。适配器模式。

于 2010-11-20T12:35:55.453 回答
1

您可以使用sigaction(2)and alarm(2),它们都是 POSIX。您使用 sigaction 为超时设置回调操作,然后使用警报设置计时器,然后进行阻塞呼叫。如果阻塞调用没有在您选择的超时时间内完成(以秒为单位;如果您需要更精细的粒度,您可以使用setitimer(2)),则阻塞调用将被中断。

请注意,C 中的信号有些复杂,并且对您在信号处理程序中可以执行的操作有相当繁重的限制。

这个页面很有用而且相当简洁: http ://www.gnu.org/s/libc/manual/html_node/Setting-an-Alarm.html

于 2010-11-20T17:21:09.257 回答
0

关于

如果阻塞的调用永远不会返回,那么第二个线程会发生什么?

我相信如果没有被调用函数(或库)的合作,将无能为力“干净”意味着清理该线程拥有的所有资源,包括内存、其他线程、锁、文件、文件锁、套接字、GPU 资源……干净,你确实可以杀死失控的线程。

于 2018-03-27T21:04:51.973 回答