如何让C函数有效地等待Qthread完成工作?

时间:2012-04-13 18:06:33

标签: qt

我有一个有趣的问题。使用Qt处理C ++项目。跨平台项目,但在Win上开发。

我有一个C风格的回调函数。它需要是C风格,我别无选择。 在该C风格回调函数中完成的工作是重要且时间敏感的。因此,我有一些Qthread线程帮助完成工作量。

我没有使用Qt线程的run方案,而是使用QThreads,如QThread文档底部所述。 http://qt-project.org/doc/qt-5.0/qthread.html#wait

为了清楚起见,我正在使用QThread:

QThread *thread = new QThread;
Worker *worker = new Worker;
worker->moveToThread(thread);
thread->start();
QMetaObject::invokeMethod(worker, "doWork", Qt::QueuedConnection);

线程在应用程序启动时生成,并使用QMetaObject :: invokeMethod提供。

挑战是在QThread线程完成工作之前,没有C回调函数做“任何事情”(以有效的方式)。我想让回调函数等待它不会与工作线程竞争cpu(所以没有繁忙的虚拟循环)。我也可以使用像sleep()这样的东西,但是效率不高,因为如果线程“早”完成,就会浪费睡眠。我想过从工作人员发送信号,但问题是我的回调是一个C函数,所以我看不出它是如何捕获Qt信号的。

3 个答案:

答案 0 :(得分:0)

好的,考虑这样的方法。让你的回调函数除了设置一个全局的标志(或递增一些计数器)之外什么都不做,并显示你的函数是否被调用(或多少次)。然后imlement类继承自QObject(有插槽)。您订阅了线程完成信号。当发出信号时,你只需要调用另一个函数(使用回调函数的逻辑),这是lib调用它的次数。它会起作用吗?

答案 1 :(得分:0)

如果您有“手头”的线程,并且您完全确定该线程在完成工作后将自行退出。

http://qt-project.org/doc/qt-4.8/qthread.html#wait

BUT!

如果您不希望自己的线程退出,只想等到工作人员发出一些信号,您可能会这样做:

QEventLoop loop;
connect(worker, SIGNAL(workFinished()), &loop, SLOT(quit()));
QMetaObject::invokeMethod(worker, "doWork", Qt::QueuedConnection);
loop.exec();

答案 2 :(得分:0)

这个问题很安静,但它出现在“相关问题”中。由于这个问题很有趣,答案对Qt用户有用,我决定给出一个详细的答案。

要等待其他QThread中的函数完成,可以采用多种策略:

  1. 使用Qt::BlockingQueuedConnection
  2. 使用天真的while(anAtomicBoolean){}循环。
  3. 使用更聪明的while(anAtomicBoolean){QThread::yieldCurrentThread();}循环。
  4. 使用QWaitCondition
  5. 使用QSemaphore
  6. 策略2和3看起来像坏主意,因为等待线程在等待检查循环条件时必须处于活动状态。但是,策略3具有为其他线程和进程释放CPU时间的优势。

    其他3种策略的优点是可以在等待时让线程休息,并且应该非常等效。但是,解决方案1和4不允许您(或至少很容易)同时在不同的线程中运行多个worker。因此,最好的解决方案是使用信号量。

    QSemaphore semaphore(2)
    worker1.sem = &semaphore;
    worker2.sem = &semaphore;
    semaphore.acquire(2);
    QMetaObject::invokeMethod(&worker1, "doWork", Qt::QueuedConnection);
    QMetaObject::invokeMethod(&worker2, "doWork", Qt::QueuedConnection);
    semaphore.acquire(2); // each worker release(1) when done
    semaphore.release(2);
    

    为了证明我的主张,我已经做了一些基准测试(如果有人有兴趣,我会在稍后提供代码)。我使用QueryThreadCycleTime()来获取等待线程消耗的周期数。像这样:

    QueryThreadCycleTime(hThread, &start);
    QMetaObject::invokeMethod(&worker, "doWork", Qt::BlockingQueuedConnection);
    QueryThreadCycleTime(hThread, &stop);
    

    基准测试结果如下图所示: Result graph