从不同QThread访问QOBject方法的安全性



我正在编写一个应用程序,该应用程序使用一个主应用程序线程和第二个线程(并且没有其他线程预见(。第二个线程被实现为"工人",这意味着我不扩展QThread类,而是将工作对象移至线程。我们在这里举了一个小例子:

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

Worker::work直接访问_myObj->member2();是否安全?如果没有,我可以通过信号&amp;老虎机机制?如果我应该...为什么到底?

直接访问_myobj-> member2((是安全的吗?来自工人::工作?

很可能不是。这将取决于实现,但总体而言,跨线程的呼叫方法很少安全。为了使其安全,您需要将锁/互斥符应用到该方法(直接和间接(的任何访问的内容,并确保您从该方法调用的所有内容也是线程安全的。值得庆幸的是QT Signal&amp;插槽抽象了,因此您不必担心。

如果没有,我可以通过信号&amp;插槽机制?

您应该以以下方式:

QObject::connect(_thread, &QThread::started, _worker, &MyObject::work);

删除直接调用到MyObject::work()。还考虑:

QObject::connect(_thread, &QThread::finished, _thread, &QThread::deleteLater);

请注意,QObject::connect 是thead-safe 。它可以随时从任何线程中的任何对象上的任何线程调用。

如果我应该...为什么呢?

在与您的不同线程中调用对象本质上是危险的。您调用线程的方法安全吗?使用QObjects,发送信号和调用插槽还有其他问题。work()会这样做吗?如果您在拨打work()时,线程中的事件循环为不是运行应用程序会崩溃或至少无法发送信号。通过连接QThread::startedMyObject::work,您可以确保在运行线程中正确调用该方法,并以正确的顺序进行运行事件循环。

没有信号的完整性&amp;插槽您应该这样做,以确保它可以按预期工作:

if(_thread->isRunning())
    _worker->work();

最新更新