簡體   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