繁体   English   中英

你如何等待 `QtConcurrent::run` 在没有线程阻塞的情况下完成?

[英]How do you wait for `QtConcurrent::run` to finish without thread blocking?

嘿,这应该是一个非常简单的问题。 简单的说:

  • 想在另一个线程中运行一个函数。
  • 需要等待函数完成。
  • 不想在等待时冻结线程。
  • 换句话说,我想使用一个事件循环。

这是冻结示例:

extern void sneed()
{
    QEventLoop wait;
    wait.exec();
}
int main( int argc, char *argv[] )
{
    QApplication a(argc, argv);
    {
        // this starts a tui
        QConsoleToolkit::s_CursesController.start( QCD::CursesEngine::Engine_Thread_Stdout_Monitor );
    }

    ct_Start( "Sneed" );
    QFuture<void> ff = QtConcurrent::run(sneed);
    ff.waitForFinished(); // This freezes the tui
    ct_Finish( "Chuck" );
}

我尝试在主线程中使用 QEventLoop 而不是ff.waitForFinished() ,但我无法弄清楚如何在ff完成时发出信号,因为 QFuture 不是 QObject,并且没有我可以绑定的finished信号至:

https://doc.qt.io/qt-6/qfuture.html

我尝试通过引用传递 QObject 以从中发出信号,但无法编译。

我在这里想念什么?

解决方案来自一个名为 QFutureWatcher 的简单类:

doc.qt.io/qt-5/qfuturewatcher.html

这是一些在不同线程中运行 lambda 并接收其值的示例代码。

template <class T>
auto asynchronous( auto &&lambda )
{
    QEventLoop wait;
    QFutureWatcher<T> fw;
    fw.setFuture( QtConcurrent::run(lambda) );
    QObject::connect   ( &fw, &QFutureWatcher<T>::finished, &wait, &QEventLoop::quit );
    wait.exec();
    QObject::disconnect( &fw, &QFutureWatcher<T>::finished, &wait, &QEventLoop::quit );
    return fw.result();
}

使用该函数将如下所示:

int n(0);
ct_Start(n); // 0 - Running in main thread
n = asynchronous<int>([&n](){
    // Running in background thread.
    // Mainthread is waiting for this lambda to finish
    // but mainthread is not locked. 
    // User Interface will still function.
    for ( int i = 0; i < 100000; i++ ){
        ct_Debug(n++); 
    };
    return n;
});
ct_Finish(n); // 100000

注意:在 Qt 框架中找不到ct_Debug ct_Start ct_Finish 它们正在调试 TUI 的宏。

我想你误解了我的评论。 这真的只是一个后续评论。 这不是一个真正的答案,因为我不是 Qt 专家,但我将其发布为“答案”,以便我可以包含一个代码示例。

我在之前的评论中试图问的问题是,你为什么不能这样做?

extern void sneed() {
    ...
}

void sneed_wrapper() {
    sneed();
    ...emit a signal...
}

int main( int argc, char *argv[] )
{
    ...
    ct_Start( "Sneed" );
    QFuture<void> ff = QtConcurrent::run(sneed_wrapper);
    ...
}

您说过,如果运行sneed()的线程会发送一个信号,该信号会在线程结束时提醒主事件循环,那么您可以解决您的问题。

好的,那么为什么不让线程运行sneed_wrapper() ,如上所示? sneed_wrapper()运行sneed() ,然后当sneed()完成时,它可以在 Qt* 中做任何事情来发送将警告主循环的信号。


* 我有没有提到我不知道 Qt?

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM