如何让C函数高效地等待Qthread完成工作?
我有一个有趣的问题。用Qt处理C++项目。跨平台项目,但在双赢的基础上发展 我有一个C风格的回调函数。它必须是C风格,我没有选择。 在C风格的回调函数中所做的工作非常重要,并且对时间非常敏感。因此,我有一些Qthread线程帮助处理工作负载 我并没有对Qt线程使用run方案,而是使用QThread,如QThread文档底部所述 为了清楚起见,我使用QThread如下:如何让C函数高效地等待Qthread完成工作?,qt,Qt,我有一个有趣的问题。用Qt处理C++项目。跨平台项目,但在双赢的基础上发展 我有一个C风格的回调函数。它必须是C风格,我没有选择。 在C风格的回调函数中所做的工作非常重要,并且对时间非常敏感。因此,我有一些Qthread线程帮助处理工作负载 我并没有对Qt线程使用run方案,而是使用QThread,如QThread文档底部所述 为了清楚起见,我使用QThread如下: QThread *thread = new QThread; Worker *worker = new Worker; work
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信号的。
好的,考虑一下这种说法。让您的回调函数除了设置一些全局标志(或增加一些计数器)并显示您的函数是否被调用(或调用了多少次)之外,什么都不做。然后从QObject继承IMElement类(以具有插槽)。您将其订阅到线程完成信号。当发出信号时,您只需调用另一个函数(使用回调函数的逻辑),它被lib调用了很多次。这样行吗?让您的回调函数除了设置一些全局标志(或增加一些计数器)并显示您的函数是否被调用(或调用了多少次)之外,什么都不做。然后从QObject继承IMElement类(以具有插槽)。您将其订阅到线程完成信号。当发出信号时,您只需调用另一个函数(使用回调函数的逻辑),它被lib调用了很多次。它会工作吗?
如果你有线程“在手”,并且你完全确定线程在完成工作后会自动退出 但是 如果您不想退出线程,只想等待工作线程发出一些信号,您可以这样做:QEventLoop loop;
connect(worker, SIGNAL(workFinished()), &loop, SLOT(quit()));
QMetaObject::invokeMethod(worker, "doWork", Qt::QueuedConnection);
loop.exec();
若您有线程“在手”,并且您完全确定该线程将在完成工作后退出
但是
如果您不想退出线程,只想等待工作线程发出一些信号,您可以这样做:
QEventLoop loop;
connect(worker, SIGNAL(workFinished()), &loop, SLOT(quit()));
QMetaObject::invokeMethod(worker, "doWork", Qt::QueuedConnection);
loop.exec();
这个问题很古老,但它出现在“相关问题”中。由于这个问题很有趣,而且答案对Qt用户很有用,所以我决定给出一个详细的答案 要在不同的QThread中等待函数完成,可以使用多种策略:
Qt::BlockingQueuedConnection
while(anAtomicBoolean){}
循环while(anAtomicBoolean){QThread::yieldCurrentThread();}
循环QWaitCondition
QSemaphore
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);
基准测试结果如下图所示:
这个问题很老,但它出现在“相关问题”中。由于这个问题很有趣,而且答案对Qt用户很有用,所以我决定给出一个详细的答案 要在不同的QThread中等待函数完成,可以使用多种策略:
Qt::BlockingQueuedConnection
while(anAtomicBoolean){}
循环while(anAtomicBoolean){QThread::yieldCurrentThread();}
循环QWaitCondition
QSemaphore
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);
基准测试结果如下图所示:
你不能用Qt类包装C函数并捕捉信号吗?不,我不能。C函数不仅仅是一个C函数,它是一个回调函数。图书馆的一部分。我不能改变它的本质,我只能实现它的身体。我无法控制调用回调的对象/用户,我需要将其保留为C回调函数。你不能用Qt类包装C函数并在那里捕获信号吗?不,我不能。C函数不仅仅是一个C函数,它是