Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/asp.net-core/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何让C函数高效地等待Qthread完成工作?_Qt - Fatal编程技术网

如何让C函数高效地等待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

我有一个有趣的问题。用Qt处理C++项目。跨平台项目,但在双赢的基础上发展

我有一个C风格的回调函数。它必须是C风格,我没有选择。 在C风格的回调函数中所做的工作非常重要,并且对时间非常敏感。因此,我有一些Qthread线程帮助处理工作负载

我并没有对Qt线程使用run方案,而是使用QThread,如QThread文档底部所述

为了清楚起见,我使用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信号的。

好的,考虑一下这种说法。让您的回调函数除了设置一些全局标志(或增加一些计数器)并显示您的函数是否被调用(或调用了多少次)之外,什么都不做。然后从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
  • 策略2和3看起来像是坏主意,因为等待线程在等待检查循环条件时必须处于活动状态。然而,策略3的优势在于为其他线程和进程释放CPU时间

    其他3种策略的优点是在等待时将线程置于静止状态,它们应该是相当等效的。但是,解决方案1和4不允许(或至少不容易)同时在不同线程中运行多个辅助线程。因此,最好的解决方案是使用信号量

    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
  • 策略2和3看起来像是坏主意,因为等待线程在等待检查循环条件时必须处于活动状态。然而,策略3的优势在于为其他线程和进程释放CPU时间

    其他3种策略的优点是在等待时将线程置于静止状态,它们应该是相当等效的。但是,解决方案1和4不允许(或至少不容易)同时在不同线程中运行多个辅助线程。因此,最好的解决方案是使用信号量

    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函数,它是