Qt:QFuture / QtConcurrent超时函数调用

时间:2013-11-11 09:42:32

标签: c++ qt

我需要一个超时函数调用。我主要使用Qt(4.7.3,4.8.5),因此我试图找到Qt的解决方案。两个类QFuture和QtConcurrent似乎做了我需要的99%,但我找不到超时函数调用的可能性。

我的问题: 我有我的测试仪(gtest),我测试了一个可以在无限循环中结束的函数=>所以我想测试这个来解决这个问题[s](这个函数是内部的极端复杂:-()。我想添加一个超时时间来突破,如果有一个无限循环=>所以我可以告诉测试器出错了(无限循环),我将终止线程。

我已经找到了类似的东西:

QtConcurrent::run(............,30000 /*30 seconds timeout)*/;

有人知道我该怎么做吗? (如果可以使用原生C ++,或者提升,或者......你也可以告诉我你的解决方案)

4 个答案:

答案 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();
}

终止调用将强制停止线程,从而停止执行您的功能。但请注意,线程无法清除,并且函数使用的任何资源都无法正确释放。


旧答案:
您可以使用QFutureWatcherQTimer和帮助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);