2010-11-20 74 views
3

所以情况就是这样。我有一个C++库,它正在进行一些进程间通信,使用wait()函数来阻塞和等待传入的消息。难点是我需要定时等待,如果在指定的时间内没有收到消息,它将返回一个状态值。如何在阻塞呼叫周围实现定时等待?

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

这是我怎么会做这样一个忙等循环,在伪代码:

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

我不尽管如此,你还是需要忙于等待处理器周期。而且我也不想仅在循环中添加sleep()调用以避免处理器负载,因为这意味着响应速度较慢。我想要一些适当的块和中断。如果更好的解决方案涉及线程(这似乎很可能),我们已经使用boost::thread,所以我宁愿使用它。

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

编辑补充:我的很大一部分关注点在于,程序中的这一点对性能至关重要,并且对于避免竞争条件或内存泄漏至关重要。因此,虽然“使用两个线程和一个计时器”是有益的建议,但我仍然试图找出如何以一种安全和正确的方式实际实现它,并且我可以很容易地看到自己在代码中犯下新手的错误,甚至不知道我做了什么。因此,一些实际的示例代码将非常感谢!另外,我对多线程解决方案有所担忧:如果我使用“在第二个线程中放置阻塞调用并在该线程上执行定时等待”方法,那么第二个线程会发生什么阻止呼叫永不返回?我知道在第一个线程中的等待时间会返回,我会看到没有答案发生并继续进行,但是我是否已经“泄漏”了一个将永远处于阻塞状态的线程?有什么办法可以避免这种情况? (有什么办法可以避免这种情况,避免泄漏第二个线程的内存?)如果阻塞调用没有返回,我需要的完整解决方案需要避免发生泄漏。

回答

1

您可以使用sigaction(2)alarm(2),它们都是POSIX。您使用sigaction为超时设置回调动作,然后使用闹铃设置一个计时器,然后进行阻止呼叫。如果阻塞呼叫在您选择的超时时间内未完成,则会中断呼叫(以秒为单位;如果您需要更精细的粒度,则可以使用setitimer(2))。

请注意,C语言中的信号有点多毛,并且在信号处理程序中可以做的事情有相当繁重的限制。

本页面是有用的,相当简洁: http://www.gnu.org/s/libc/manual/html_node/Setting-an-Alarm.html

+0

谢谢!我想这听起来像我想要的 - 但我没有足够的细节来了解如何去做。特别是,我不知道如何正确设置一个信号来中断阻塞调用并永久停止它,而不是在中断处理程序退出后再回到它。你能否就如何做到这一点添加一些解释? – 2010-11-20 21:03:25

+1

从我的答案中的GNU链接:“为了能够使用闹钟功能来中断可能无限期阻塞的系统调用,使用sigaction注册信号处理程序时不要设置SA_RESTART标志很重要。我会尝试。那么问题是当它的基本操作返回EINTR时,库代码会做什么。如果幸运的话,你正在使用的库会有某种你可以从你的信号处理程序调用的“停止”函数,或者它只会从EINTR上的阻塞调用中返回。如果它更持久并且在EINTR上再次阻止,生活就会更加困难。 – 2010-11-21 16:52:04

+0

好的,这开始有意义 - 我错过了那条线,也没有意识到SA_RESTART存在,或者中断的代码可能发生任何事情,除了它继续停止的地方。感谢您指出了这一点! (我不确定在这种情况下库代码的作用,或者我们可以在多大程度上依赖它,因为它有钩子让人们为不同的通信库添加不同的代码,但我会发现的。) – 2010-11-22 21:43:03

1

你想要的是类似select(2),这取决于你的目标操作系统。

+0

喜欢的东西,是的。这似乎是特定于文件描述符,虽然这是与任意库调用。根据我使用的版本,它可能会或可能不会使用深层文件描述符,但我无法访问它们。不过谢谢! – 2010-11-20 20:54:57

1

这听起来像你需要一个'监视器',能够通过共享互斥量(通常)向线程通知资源的可用性。在Boost.Thread condition_variable可以完成这项工作。

1

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

1

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

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

+0

不错,但是如果这个阻止呼叫不会解除阻塞,那么我的单独线程会发生什么?如果我在连续运行的程序中每分钟执行一次该怎么办? – 2010-12-16 06:51:28