Безопасность доступа к методу QObject из разных QThread - PullRequest
0 голосов
/ 25 апреля 2018

Я пишу приложение, которое использует один основной поток приложения и второй поток (и других потоков не предвидится). Второй поток реализован как «рабочий», что означает, что я не расширяю класс 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();
}

Безопасен ли прямой доступ _myObj->member2(); из Worker::work? Если нет, должен ли я заменить этот вызов на механизм сигнала и слота? Если я должен ... почему именно?

1 Ответ

0 голосов
/ 26 апреля 2018

Безопасен ли прямой доступ _myObj-> member2 ();от Worker :: work?

Скорее всего нет.Это будет зависеть от реализации, но, вообще говоря, вызов методов между потоками редко бывает безопасным.Чтобы сделать это безопасным, вам необходимо применить блокировки / мьютексы к тому, к чему обращаются (прямо или косвенно) из этого метода, и обеспечить, чтобы все, что вы вызываете из этого метода, также было поточно-ориентированным.К счастью, сигнал Qt и слоты абстрагируют это, так что вам не нужно об этом беспокоиться.

Если нет, я должен заменить этот вызов на механизм сигнала и слота?

Вы должны вследующим образом:

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

Удалить прямой вызов MyObject::work().Также учтите:

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

Обратите внимание, что QObject::connect является безопасным для жизни .Он может быть вызван из любого потока любого объекта в любом потоке в любое время.

Если я должен ... почему именно?

Вызов объекта в другом потокечем ваш опасен по своей природе.Безопасен ли метод, который вы называете потоком?С QObjects существует дополнительная проблема отправки сигналов и вызова слотов.work() делает это?Если к тому времени, когда вы вызовете work(), цикл обработки событий в потоке будет NOT , запущенное приложение завершится сбоем или, по крайней мере, не отправит сигнал.Соединяя QThread::started и MyObject::work, вы гарантируете, что метод вызывается правильно в работающем потоке и с циклом запуска событий в правильной последовательности.

Для полноты без сигналов и слотов вы должны сделать это, чтобы убедиться, что он будетработать как положено:

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