我有一个有趣的问题。使用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信号的。
答案 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中的函数完成,可以采用多种策略:
Qt::BlockingQueuedConnection
。while(anAtomicBoolean){}
循环。while(anAtomicBoolean){QThread::yieldCurrentThread();}
循环。QWaitCondition
。QSemaphore
。策略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);