[英]C++: How to implement a timeout for an arbitrary function call?
不幸的是,我需要调用有时不会在给定时间内终止的库函数。 有没有办法调用该函数,但如果它不在n
秒内终止就中止它?
我无法修改函数,所以我不能直接将中止条件放入其中。 我必须在外部为函数添加超时 。
它可能是一个可能的解决方案,将其作为(提升)线程启动,然后我可以在一段时间后终止它? 会有类似的东西吗? 我实际上认为该函数不是线程安全的,但如果我将它作为唯一的单线程运行则无关紧要,对吧? 还有其他(更好的)解决方案吗?
你可以产生一个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调用的作用,因为它可能永远不会释放它所获得的资源。
我认为实现这一目标的唯一安全方法是生成一个单独的沙箱进程,该进程将库函数作为应用程序的代理调用。 您需要在应用程序和代理之间实现某种类型的IPC。 在读取IPC回复时实现超时非常简单。 如果读取因超时而失败,则可以安全地终止代理,而不会危及应用程序的运行状况。
你所说的通常被称为“看门狗”系统。 监视程序通常是第二个线程,它检查所有其他线程的状态。 看门狗通常设置为定期运行。 如果没有从其他线程收到响应,则监视程序可以通知用户,或者如果可以安全地(取决于您的应用程序)可以杀死有问题的线程。
线程的问题是在线程终止后你将无法释放一些资源。 如果您没有获得必须释放的资源,那么请使用线程。
Boost.Test的execution_monitor做你想要的:
问题是, 如果没有函数支持的进程内解决方案,您最终可能会出现无效状态。
示例:在进行内存分配时终止线程时,进程堆可能已损坏。
因此,您可以终止呼叫,但之后您还必须终止该过程。 在许多情况下,破坏性副作用的可能性很小,但我不打赌我的计算。
正如Ben Straub建议的那样,你可以孤立线程:把它放在最低优先级并让它运行无穷大。 这当然只是一个有限的解决方案:如果线程消耗资源(可能),它们将减慢系统速度,每个进程的线程也有限制(通常是由于线程堆栈的地址空间)。
通常,我更喜欢外部流程解决方案。 一个简单的模式是这样的:
将输入数据写入文件,以文件作为参数启动外部进程。 外部进程将进度(如果有)写入可以监视的磁盘文件,甚至可以允许进程从其开始的位置继续。 结果将写入磁盘,父进程可以读取它们。
当你终止进程时,你仍然需要处理同步对外部资源(如文件)的访问,以及如何处理被遗弃的mutices,半写文件等。但它通常是一种强大的解决方案。
“不幸的是,我需要调用有时不会在给定时间内终止的库函数。有没有办法调用函数,但如果它在n秒内没有终止就会中止它?”
最简洁的答案是不。 这通常是麻烦...调用本身必须在某个时间终止(实现自己的超时),但是阻塞调用通常是麻烦的(例如gethostbyname()),因为这取决于他们(或系统)超时,而不是你的。
因此,只要有可能,尝试在必要时使代码在线程中运行干净 - 代码本身必须检测并处理错误。 它可以发送消息和/或设置状态,以便主(或另一个)线程知道发生了什么。
个人偏好,在高度可用的系统中,我喜欢我的线程经常旋转(没有忙碌锁定),具有特定的超时,调用非阻塞功能,以及准确的退出条件。 一个全局或特定于线程的'done'变量可以实现干净的退出。
使用孤立进程,启动它并计算执行时间。 如果时间不够,请调用操作系统将其终止。
如何避免种族冲突。 在这种模式上:
创建一个存储在args中的文件(当然,所有内容都作为VAL传递)。 孤立进程只允许从该文件中读取数据。
孤立处理输入数据,创建带有结果值的输出文件并关闭它。
只有当一切都完成后,orphan才会删除输入文件,这一事实表明主进程已完成工作。
这避免了读取半写文件的问题,因为主设备首先注意到输入文件的缺失,打开以读取输出文件,这肯定已经完成(因为在删除输入之前关闭,并且OS调用堆栈是顺序的)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.