c++ - 从不同的 QThread 访问 QObject 方法的安全性
问题描述
我正在编写一个应用程序,它使用一个主应用程序线程和一个第二个线程(并且没有预见到其他线程)。第二个线程被实现为一个“worker”,这意味着我不扩展 QThread 类,而是将我的 worker 对象移动到一个 Thread。我们在这里做了一个小例子:
文件:myObject.h
#pragma once
#include <QObject>
#include <worker.h>
class MyObject : public QObject
{
Q_OBJECT
public:
MyObject(){}
void member1();
void member2();
Worker* _worker;
};
文件:myObject.cpp
#include "myobject.h"
#include <QThread>
#include <QDebug>
void MyObject::member1()
{
qDebug() << "MyObject::member1()";
QThread* _thread = new QThread;
_worker = new Worker(this);
_worker->moveToThread(_thread);
_thread->start();
_worker->work();
}
void MyObject::member2()
{
qDebug() << "MyObject::member2()";
}
文件:worker.h
#pragma once
#include <QObject>
class MyObject;
class Worker : public QObject
{
Q_OBJECT
public:
Worker(MyObject* myObj) : _myObj(myObj) {}
void work();
private:
MyObject* _myObj;
};
文件:myworker.cpp
#include <worker.h>
#include <myobject.h>
#include <QDebug>
void Worker::work()
{
qDebug() << "Worker::work()";
_myObj->member2();
}
文件 main.cpp
#include <QCoreApplication>
#include <myobject.h>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
MyObject myObject;
myObject.member1();
return a.exec();
}
_myObj->member2();
从直接访问是否安全Worker::work
?如果不是,我应该用信号和槽机制替换这个调用吗?如果我应该...为什么?
解决方案
直接访问 _myObj->member2() 是否安全?来自工人::工作?
很可能不是。这将取决于实现,但一般来说,跨线程调用方法很少是安全的。为了使其安全,您需要将锁/互斥锁应用于从该方法(直接和间接)访问的任何内容,并确保您从该方法调用的所有内容也是线程安全的。值得庆幸的是,Qt 信号和插槽将其抽象出来,因此您不必担心。
如果不是,我应该用信号和槽机制替换这个调用吗?
您应该以下列方式:
QObject::connect(_thread, &QThread::started, _worker, &MyObject::work);
删除对 的直接调用MyObject::work()
。还要考虑:
QObject::connect(_thread, &QThread::finished, _thread, &QThread::deleteLater);
请注意,这QObject::connect
是安全的。它可以随时从任何线程中的任何对象上的任何线程调用。
如果我应该...为什么?
在与您不同的线程中调用对象本质上是危险的。你调用的方法是线程安全的吗?还有QObjects
一个发送信号和调用槽的额外问题。这样做work()
吗?如果当您调用work()
线程中的事件循环时未运行您的应用程序将崩溃或至少无法发送信号。通过连接QThread::started
,MyObject::work
您可以确保在正在运行的线程中正确调用该方法,并以正确的顺序运行事件循环。
为了没有信号和插槽的完整性,您应该这样做以确保它按预期工作:
if(_thread->isRunning())
_worker->work();
推荐阅读
- python - TypeError: 'NoneType' object is not callable (Beginner) Python
- scala - 如何计算火花Scala中2行之间的时间差
- angular - 使用 Angular 和 Apollo 进行 GraphQL 查询
- android - 检测设备是否有键盘,或者是触摸设备
- html - React.js 样式组件:添加 HTML 属性
- javascript - 如何识别剑道网格中的子网格过滤器列名
- javascript - RxJS 依次执行两个 observable
- javascript - 单击事件未触发,但鼠标悬停工作
- python - 是否可以在 Tensorflow 中输入动态形状矩阵?
- mqtt - 如何订阅多个 MQTT 客户端以排长队