Создание QNetworkAccessManager в другом потоке - PullRequest
0 голосов
/ 01 июня 2018

У меня есть QNetworkAccessManager, созданный в другом потоке.Сеть предназначена для использования только в MyMegaThread.
QNetworkAccessManager создается из метода run потока:

mp_manager.reset(new QNetworkAccessManager{this});

При создании я получаю такое сообщение в консоли:

QObject: Cannot create children for a parent that is in a different thread.
(Parent is MyMegaThread(0x237eabd0ee0), parent's thread is QThread(0x237e70742a0), current thread is MyMegaThread(0x237eabd0ee0)

Это сообщение совершенно безвредно, но мне интересно, какой родитель должен иметь менеджер.
Я подозреваю, что это происходит потому, что экземпляр MyMegaThread создается в главном потоке, но мне нужен родитель, созданный в MyMegaThread.

Какой идиоматический способ сделать это?

Ответы [ 2 ]

0 голосов
/ 01 июня 2018

Нет, сообщение совсем не безобидно.Созданный вами объект имеет нулевого родителя и не имеет ссылки на ассоциацию потоков, поэтому его метод thread() может в любой момент вернуть висячий указатель.Он не может безопасно использовать таймеры и принимать вызовы между потоками.В основном это бесполезный объект, и вы просите нанести удар по неопределенному поведению.Это должно быть не предупреждение, а провал.Qt оказал вам плохую услугу, позволив вам продолжить.

Идиоматический способ сделать это, прежде всего, не выводить из QThread.QThread это дескриптор нити.Оборачивает системный ресурс.Поместите все свои функциональные возможности в обычный QObject, переведенный в QThread.Идиоматический способ бесконечно «делать вещи» в любом потоке, включая основной, состоит в использовании таймера нулевой длительности.Обратите внимание, что таймеры с нулевой длительностью не имеют никакого отношения к синхронизацииПо сути, они являются дескрипторами цикла событий, называя их таймером.Обходной путь см. в этом ответе .

0 голосов
/ 01 июня 2018

Родитель - MyMegaThread (0x237eabd0ee0), родительский поток - QThread (0x237e70742a0), текущий поток - MyMegaThread (0x237eabd0ee0)

Эта проблема не относится к QNetworkAccessManager 100 *.

Вот демонстрационная версия для воспроизведения предупреждения.

#include <QDebug>
#include <QThread>

class MyMegaThread : public QThread
{
    Q_OBJECT
public:
    using QThread::QThread;

protected:
    void run() override {
        qDebug()<<QThread::currentThread()<<this->thread();
        new QObject(this);
    }
};

// main
MyMegaThread m;
m.start();

Вывод:

MyMegaThread(0x60fe18) QThread(0x16a7c48)

Это правило QObject:

Все объекты QObjectдолжны жить в том же потоке, что и их родитель.Следовательно:

setParent () завершится ошибкой, если два вовлеченных объекта QObject живут в разных потоках.Когда QObject перемещается в другой поток, все его дочерние элементы также автоматически перемещаются.moveToThread () завершится ошибкой, если у QObject есть родительский объект.Если объекты QObject создаются в QThread :: run (), они не могут стать дочерними объектами объекта QThread, поскольку QThread не живет в потоке, который вызывает QThread :: run ().

http://doc.qt.io/qt-5/qobject.html#thread-affinity

Необходимо убедиться, что этот код new QObject, работающий QThread, совпадает с указанным родительским QObject потоком.

mp_manager.reset(new QNetworkAccessManager{this});
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...