C ++:如何实现任意函数调用的超时?

时间:2009-05-18 21:20:08

标签: c++ function timeout abort

不幸的是,我需要调用有时不会在给定时间内终止的库函数。有没有办法调用该函数,但如果它没有在n秒内终止,则中止它?

我无法修改该功能,所以我不能直接将中止条件放入其中。我必须在外部添加超时功能

是否可能将解决方案作为(提升)线程启动,然后我可以在一段时间后终止它?会有类似的东西吗?我实际上认为该函数是线程安全的,但如果我将它作为唯一的单线程运行则无关紧要,对吧?还有其他(更好的)解决方案吗?

9 个答案:

答案 0 :(得分:18)

您可以产生boost::thread来调用API:

boost::thread api_caller(::api_function, arg1, arg2);
if (api_caller.timed_join(boost::posix_time::milliseconds(500)))
{
    // API call returned within 500ms
}
else
{
    // API call timed out
}
但是,

Boost不允许你杀死工作线程。在这个例子中,它只是孤立的。

你必须要小心API调用的作用,因为它可能永远不会释放它所获得的资源。

答案 1 :(得分:15)

我认为实现这一目标的唯一安全方法是生成一个单独的沙箱进程,该进程将库函数作为应用程序的代理调用。您需要在应用程序和代理之间实现某种类型的IPC。在读取IPC回复时实现超时非常简单。如果读取因超时而失败,则可以安全地终止代理,而不会危及应用程序的运行状况。

答案 2 :(得分:8)

你所说的通常被称为“看门狗”系统。监视程序通常是第二个线程,它检查所有其他线程的状态。看门狗通常设置为定期运行。如果没有收到来自其他线程的响应,监视程序可以通知用户,甚至可以安全地杀死有问题的线程(取决于你的应用程序)。

答案 3 :(得分:3)

线程的问题是在线程终止后你将无法释放一些资源。如果您没有获得必须释放的资源,那么请使用线程。

答案 4 :(得分:3)

答案 5 :(得分:3)

问题在于,如果没有函数支持的进程内解决方案 ,最终可能会出现无效状态。

示例:在进行内存分配时终止线程时,您的进程堆可能已损坏。

因此您可以终止呼叫,但是您还必须终止该过程。在许多情况下,破坏性副作用的可能性很小,但我不打赌我的计算。

正如Ben Straub建议的那样,你可以孤立线程:把它放在最低优先级并让它运行无限。这当然只是一个有限的解决方案:如果线程消耗资源(可能),它们将减慢系统速度,每个进程的线程也有限制(通常是由于线程堆栈的地址空间)。

一般来说,我更喜欢外部流程解决方案。一个简单的模式是:
将输入数据写入文件,以文件作为参数启动外部进程。外部进程将进度(如果有)写入可以监视的磁盘文件,甚至可以允许进程从其开始的位置继续。结果将写入磁盘,父进程可以读取它们。

当你终止这个过程时,你仍然需要处理同步对外部资源(如文件)的访问,以及如何处理被遗弃的变种,半写文件等等。但它通常是一种强大的解决方案。 / p>

答案 6 :(得分:1)

您需要的是一个线程和Future Object,它可以保存函数调用的结果。

有关使用提升的示例,请参阅here

您需要在超时后检查未来,如果未设置,则采取相应措施。

答案 7 :(得分:1)

使用Orphan进程,启动它并计算执行时间。如果时间不够,请调用操作系统将其删除。

如何避免种族冲突。在这种模式上:

  • 创建一个存储在args中的文件(当然,所有内容都作为VAL传递)。 孤儿进程只允许从该文件中读取数据。

  • 孤儿处理输入数据,创建一个带有结果值的输出文件并将其关闭。

  • 只有当一切都完成后,orphan才会删除输入文件,这表明主进程已完成工作。

这避免了读取半写文件的问题,因为主设备首先注意到输入文件的缺失,打开以读取输出文件,这肯定已经完成(因为在删除输入之前关闭,并且OS调用堆栈是顺序的)。

答案 8 :(得分:1)

“不幸的是,我需要调用一个有时不会在给定时间内终止的库函数。有没有办法调用函数,但是如果它在n秒内没有终止就会中止它?”

简短的回答是否定的。这通常是麻烦......调用本身必须在某个时间终止(实现自己的超时),但阻塞调用通常是麻烦(例如gethostbyname()),因为这取决于他们(或系统)的超时,而不是你的。

因此,只要有可能,尝试在必要时使代码在线程中运行干净 - 代码本身必须检测并处理错误。它可以发送消息和/或设置状态,以便主(或另一个)线程知道发生了什么。

个人偏好,在高度可用的系统中,我喜欢经常旋转的线程(没有忙碌锁定),具有特定的超时,调用非阻塞功能,以及准确的退出条件。一个全局或特定于线程的'done'变量可以实现干净的退出。