我需要一个超时函数调用。我主要使用Qt(4.7.3,4.8.5),因此我试图找到Qt的解决方案。两个类QFuture和QtConcurrent似乎做了我需要的99%,但我找不到超时函数调用的可能性。
我的问题: 我有我的测试仪(gtest),我测试了一个可以在无限循环中结束的函数=>所以我想测试这个来解决这个问题[s](这个函数是内部的极端复杂:-()。我想添加一个超时时间来突破,如果有一个无限循环=>所以我可以告诉测试器出错了(无限循环),我将终止线程。
我已经找到了类似的东西:
QtConcurrent::run(............,30000 /*30 seconds timeout)*/;
有人知道我该怎么做吗? (如果可以使用原生C ++,或者提升,或者......你也可以告诉我你的解决方案)
答案 0 :(得分:1)
我专注于QtConcurrent模块,因为你在问题中提到过它。但是你也可以通过简单的QThread实现你的目标:
// A Thread calling your test function
class MyThread : public QThread {
protected:
void run() { myFunction(); }
};
// calling the function
MyThread t;
t.start();
if ( t.wait(30000) ) {
// Finished
} else {
// Not finished
// ATTENTION: USE TERMINATE WITH CARE (see QThread documentation)!
t.terminate();
}
终止调用将强制停止线程,从而停止执行您的功能。但请注意,线程无法清除,并且函数使用的任何资源都无法正确释放。
旧答案:
您可以使用QFutureWatcher
,QTimer
和帮助QEventLoop
来使用Qt执行此操作。设置并发运行,并使用观察器观察结果。使用计时器设置Timout,并在事件循环中等待任何一个结束。
// Setup eventloop, watcher and timer
QEventLoop loop;
QFutureWatcher watcher;
QObject::connect( &watcher, SIGNAL(finished()), &loop, SLOT(quit()));
QTimer::singleShot( 30000, &loop, SLOT(quit()) );
// Start function call
QFuture<T> future = QtConcurrent::run(...);
// Watch the call
watcher.setFuture( future );
// Wait until event loop finishes
loop.exec();
// Now either future has finished, or timeout was reached...
if ( future.isFinished() ) {
// Function completed!
} else {
future.cancel();
// Infinite loop...
}
答案 1 :(得分:1)
问题是如果没有线程的合作,你就无法安全地终止一个线程。该线程可能正在访问某些共享数据结构,如C运行时堆,如果它被强制终止,那么这些数据结构将保持中间变化状态,基本上已损坏。将来从程序中访问它们可能会导致崩溃或更糟。
无限循环的情况与其他不良情况无关。如果你启动的功能崩溃了程序,你如何向测试人员报告呢?
在您的情况下,您根本不相信您正在执行的代码。解决方案是在单独的进程中启动它,其安全终止由操作系统保证。通过将测试代码与测试器应用程序隔离,您可以保证可以检测到所有类型的问题,包括超时或异常终止。
答案 2 :(得分:-2)
我认为你需要找出无限循环发生的原因而不是试图修复症状。
QtConcurrent::run()
使用线程池来运行任务。您无法安全地终止线程,因此安全完成任务的唯一方法是从return
开始。
如果您仍想要超时,可以使用循环将这样的内容添加到您的函数中:
QTime t;
t.start();
// it's your loop
while( true ) {
if( t.elapsed() > 30*1000 ) {
return 1;
}
...
}
答案 3 :(得分:-2)
您可以将QTimer信号绑定到插槽:
auto process = QtConcurrent::run(...);
QTimer& timer = new QTimer();
connect(timer, &QTimer::timeout, [=, &process]() {
process.cancel();
});
timer->start(3000);
编辑:由于cancel()方法不适用于QtConcurrent :: run函数,最简单的方法是使用某种isRunning标志:
bool isRunning = true;
void runnable() {
while (isRunning) {
...
}
}
auto process = QtConcurrent::run(runnable);
QTimer& timer = new QTimer();
connect(timer, &QTimer::timeout, [=, &isRunning]() {
isRunning = false;
});
timer->start(3000);