[英]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.