如何防止std :: thread冻结QT中的GUI?

时间:2018-10-02 21:20:54

标签: c++ multithreading qt

我正在一个项目中,我将提取多个二进制文件,对其进行解码,然后将其数据转换为CSV。我认为最快的方法是将工作线程化。只需将文件加载到队列中,让线程抓取一个文件,对其进行处理,转换,输出然后消失。

我写的内容实际上很有效,但是,我无法确定如何使GUI响应,因为我有一个要更新的进度条,或者只是在处理过程中让用户将GUI移到角落数据。我相信这是因为replaceTokens(text, ["Lorem", "dolor"], expressions) 只是挂断了GUI。

在我的代码中,一旦按下按钮即可执行以下功能:

std::thread

initThread看起来像这样:

void MyExtractor::on_Execute_clicked()
{
    QStringList binary = tlmFiles.entryList(QStringList() << "*.bin",QDir::Files);
    queue.clear();
    threadPool.clear();

    if(binary.size() != 0)
    {

        foreach(QString filename, binary)
        {
            queue.emplace_back(inputDir + '/' + filename);
        }

        for (unsigned int i = 0; i < std::thread::hardware_concurrency(); ++i)
        {
            threadPool.emplace_back(&MyExtractor::initThread,this,std::ref(queue),std::ref(mut));
        }

    }
    else
    {
        message.setText("No binary files found! Please select another folder!");
        message.exec();
    }

    for (auto &&e : threadPool)
    {
        e.join();
    }
}

我一直在阅读有关QThreads的文章。从我想我一直在阅读的内容来看,似乎需要创建一个单独的线程来监视工作,而另一个线程来监视GUI?我不确定我的措词是否正确。但是,由于我正在使用void MyExtractor::initThread(std::deque<QString> &queue, std::mutex &mutex) { QString file; QString toOutput = outputDir; while(queue.size() > 0) { { std::lock_guard<std::mutex> lock(mutex); if(!queue.empty()) { file = queue.front(); queue.pop_front(); } } BitExtract *bitExtractor = new BitExtract(); if(file.size() != 0) { bitExtractor->extract(file,toOutput); } delete bitExtractor; } } 进行转换,因此我什至不知道该怎么做,而且我不确定std::thread将如何处理。有什么建议吗?

编辑:我应该清楚地说明QThreadthreadPool

1 个答案:

答案 0 :(得分:3)

如@drescherjm所述,您的问题在这里:

for (auto &&e : threadPool)
{
    e.join();
}

join()在线程完成之前不会返回,这意味着您的GUI线程将在该for循环内被阻塞,直到所有线程都退出为止,这是您要避免的。 (总是希望主/ Qt / GUI线程中的任何函数尽快返回,以便Qt的GUI事件循环可以保持响应)

避免这种情况非常简单-除非在线程产生后立即调用join(),否则仅应在线程通知您完成工作后才在线程上调用join()并即将退出。这样,join()的返回时间不会超过几毫秒。

关于如何让std::thread通知您的main / GUI线程其任务已完成,一种简单的方法是让std::thread调用QApplication::postEvent()在退出之前,并覆盖event(QEvent *)虚拟方法(无论您作为postEvent()的第一个参数传入的任何对象)都可以处理发布的事件对象(请注意,您可以使自己的{{1 }}包含您要发送到GUI线程的任何数据),方法是在QEvent上调用join(),以及线程返回结果后需要执行的任何清理和结果处理代码。