繁体   English   中英

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

[英]How to keep std::thread from freezing GUI in QT?

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

实际上,我写的东西效果很好,但是我无法弄清楚如何使GUI响应,因为我有一个要更新的进度条,或者只是让用户在处理数据时将其移至角落。 我相信这是因为std::thread只是挂断了GUI。

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

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();
    }
}

initThread看起来像这样:

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;
    }

}

我一直在阅读有关QThreads的文章。 从我想我一直在阅读的内容来看,似乎需要创建一个单独的线程来监视工作,而另一个线程来监视GUI? 我不确定我的措词是否正确。 但是,由于使用std::thread进行转换,因此我什至不知道如何执行此操作,而且我不确定QThread将如何处理此问题。 有什么建议么?

编辑:我应该明确指出threadPoolstd::vector<std::thread>

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

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

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

避免是相当简单的-而不是调用join()的线程已经催生了之后,你应该只调用join()上的线程的线程已经通知你之后,该公司已经完成其工作,即将退出。 这样, join()绝不会花费几毫秒的时间就可以返回。

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

暂无
暂无

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

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