繁体   English   中英

发出 Qt 信号的线程安全

[英]Thread safety of emitting Qt signals

我正在使用QtConcurrent::run (我知道 QtConcurrent 的其他 API 内置了对进度报告的支持,但由于其他原因我不能使用它们)。 在与主 GUI 线程不同的内部运行操作。 我还需要这个操作来通知 GUI 线程取得的进展。 所以我所做的是为我想要的操作创建一个单独的 function,它接受一个回调,该回调包含有关操作进度的信息。 然后,此回调调用位于主线程中的 QObject 上的信号。

这是一个完整的工作示例,显示了我的结构:

    #include <QCoreApplication>
    #include <QObject>
    #include <QThread>
    #include <QtConcurrent/QtConcurrent>
    
    
    namespace Operations {
    
    template<typename Callback>
    void longOperation(Callback progressCallback)
    {
        qint64 sum = 0;
        for(int i = 0; i < 100; ++i){
            QThread::msleep(400);
            sum += i;
            progressCallback(i/100.0);
        }
    }
    
    }

    class Emitter : public QObject
    {
        Q_OBJECT
    public:
        Q_INVOKABLE void doSomething()
        {
            auto progressCallback = [&](qreal p){
                emit progress(p);
            };
    
            auto lambda = [progressCallback](){
                Operations::longOperation(progressCallback);
            };
    
            QtConcurrent::run(lambda);
        }
    signals:
        void progress(qreal);
    };
    
    int main(int argc, char *argv[])
    {
        QCoreApplication a(argc, argv);
    
        Emitter emitter;
        QObject::connect(&emitter, &Emitter::progress, [](qreal progress){
            qDebug() << "Progress" << progress;
        });
        emitter.doSomething();
    
        return a.exec();
    }
    
    
    #include "main.moc"

现在我的问题是使用上面定义的progressCallback线程安全吗? 显然,回调将从与 GUI 线程不同的线程触发,因此它实际上是直接在 QObject 上调用emitter.progress()

好的,所以我现在意识到上面的代码可能不是线程安全的。 我的部分困惑是emit关键字实际上做了什么。 事实证明,它实际上并不多。 所以从另一个线程调用信号并不是最好的主意。 相反,改善这种情况的一种方法是将 progressCallback 替换为:

        auto progressCallback = [&](qreal p){
            QMetaObject::invokeMethod(this, [this, p](){ emit progress(p);}, Qt::QueuedConnection);
        };

通过这种方式,信号在发射器所在的线程上Emitter ,因为根据 Qt 文档,“当控制返回到接收器线程的事件循环时”将执行 lambda 插槽。

暂无
暂无

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

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