Russian Qt Forum

Qt => Вопросы новичков => Тема начата: virtual_root от Апрель 23, 2012, 13:43



Название: QNetworkConfigurationManager и QThread
Отправлено: virtual_root от Апрель 23, 2012, 13:43
Здравствуйте! Ребята, помогите пожалуйста разобраться.
Мне в приложении понадобилось создать 2 класса в которых я создаю объект QNetworkConfigurationManager.
Первый класс авторизуется на сервере, а второй получает данные с сервера. Второй класс является потоком.
Приложение компилируется,но в процессе работы вываливается следующая ошибка:
QObject: Cannot create children for a parent that is in a different thread.
(Parent is QNetworkAccessManager(0x8c8d808), parent's thread is MyThread(0x8da5980), current thread is QThread(0x8a9dfd0)
Я уже кучу статей перечитала как разрешить эту проблему, пересмотрела много примеров на форуме, но мне не помогло.
Привожу код класса потока, так как эта ошибка от него идет:
Код:
#ifndef MYTHREAD_H
#define MYTHREAD_H

#include <QThread>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QTimer>
#include <QNetworkConfigurationManager>
#include <Parser>
#include <Serializer>
#include <QObjectHelper>
#include <QTime>
#include "macroconfig.h"

class MyThread : public QThread
{
    Q_OBJECT
public:
    enum Status{
        PointsPay,
        FullInfo
    };
    explicit MyThread(QObject *parent = 0);
    void getPointsPay(int);
    QString getPlatform() ;
    void setServerTime(QString);
protected:
    void run();
private:
    QString m_skey;
    QNetworkAccessManager *m_manager;
    QNetworkReply *m_reply;
    QNetworkConfigurationManager m_config;
    Status m_flag;
    QTimer m_timer;
    QTimer m_TimerWating;
    QTime m_lastTimeInfo;
    QTime m_lastTimePay;
    QString m_serverTime;
    QString m_os;
    QMap<int,QVariantMap> m_pointsPay;
   
signals:
    QVariantMap succes(QVariantMap);
    QMap<int,QVariantMap> succes(QMap<int,QVariantMap>);
    QString Error(QString);
   
public slots:
        void getFullInfo();
        void finish(QNetworkReply*);
        void Error(QNetworkReply::NetworkError);
        void isOnlain();
        void setParamAndStart(QString skey);
   
};

#endif // MYTHREAD_H


Код:
#include "mythread.h"
#include <QDebug>

MyThread::MyThread(QObject *parent) :
    QThread(parent)
{
    //moveToThread(this);   если раскоментировать то функция run вообще не вызывается....
    m_manager = new QNetworkAccessManager();
    m_manager->moveToThread(this);
    connect(m_manager,SIGNAL(finished(QNetworkReply*)),this,SLOT(finish(QNetworkReply*)));
    connect(&m_TimerWating,SIGNAL(timeout()),this,SLOT(isOnlain()));
    m_lastTimeInfo.addSecs(-60);
    m_lastTimePay.addSecs(-60);
    m_os = this->getPlatform();
    m_timer.setInterval(60000);
}

void MyThread::setParamAndStart(QString skey){  // устанавливаем ключ и запускаем поток
    if (!skey.isEmpty()) {
        m_skey = skey;
        start();   // запускаем поток. Пробовала и из main.cpp но ничего не изменилось
    }
}

void MyThread::run(){
    qDebug()<<"run";
    getPointsPay(1);
    //getFullInfo();
    m_timer.start();
    exec();             // использовать собственную очередь событий
}

void MyThread::getPointsPay(int type){  // поработать с объектом QTime
   qDebug()<<__FUNCTION__<<type;
    m_flag = PointsPay;
    //if (m_lastTimePay.addSecs(30) <= QTime::currentTime()){
        QString Responce = "/?r=client/paymentplacesinfo&place_type_id=%1";
        Responce = HOST + Responce.arg(QString::number(type));
        if (m_config.isOnline()){
            m_lastTimePay = QTime::currentTime();
            m_reply = m_manager->get(QNetworkRequest(Responce));
            m_reply->moveToThread(this);
            m_reply->ignoreSslErrors();
            connect(m_reply,SIGNAL(error(QNetworkReply::NetworkError)),this,SLOT(Error(QNetworkReply::NetworkError)));
        }
        else  m_TimerWating.start(30000);
   // }

}

void MyThread::getFullInfo(){
  m_flag = FullInfo;
  if (m_lastTimePay.addSecs(30) <= QTime::currentTime()){   // проверяем как давно мы запрашивали эту информацию
        QString param = "/?r=client/getfullInfo&skey=%1&platform=%2&date=%3";
        param = HOST+param.arg(m_skey,m_os,m_serverTime);
        if (m_config.isOnline()){
            m_lastTimeInfo = QTime::currentTime();
            m_reply = m_manager->get(QNetworkRequest(param));
            connect(m_reply,SIGNAL(error(QNetworkReply::NetworkError)),this,SLOT(Error(QNetworkReply::NetworkError)));
            m_reply->ignoreSslErrors();
        }
        else  m_TimerWating.start(30000);

   }

}

void MyThread::finish(QNetworkReply* reply){
    QByteArray json = reply->readAll();
    QJson::Parser parser;
    bool ok;
    QVariantMap buffer = parser.parse (json, &ok).toMap();
    if (ok){
        if (m_flag == PointsPay){
            m_pointsPay[buffer["current"].toInt()] = buffer;
            if (buffer["current"].toInt()!=3)
                this->getPointsPay(buffer["current"].toInt()+1); // запрашиваем следующую точку оплаты
            else this->getFullInfo(); // получаем пользовательскую информацию
        }
       else {
            emit succes(buffer);  // возвращаем пользовательскую информацию
            QVariantMap news = buffer["news"].toMap();
            QList<QVariant> created = news.value("created").toList();
            QList<QVariant> modified = news.value("modified").toList();
            QList<QVariant> deleted = news.value("deleted").toList();
            if (created.isEmpty() || modified.isEmpty() || deleted.isEmpty()){
                this->getPointsPay(1);
            }
            m_timer.start();
        }
    }

}

void MyThread::Error(QNetworkReply::NetworkError error){
    switch(error)
       {

       case QNetworkReply::ConnectionRefusedError:{
           emit Error(QString::fromLocal8Bit("Сервер перегружен."));
           break;
       }

       case QNetworkReply::ContentNotFoundError:{
               emit Error(QString::fromLocal8Bit("Ошибка сервера 404."));
               break;
           }
       case QNetworkReply::HostNotFoundError:{
               emit Error( QString::fromLocal8Bit("Не найден удаленный сервер."));
               break;
           }

       default: {
               emit Error(m_reply->errorString());
               break;
           }
       }
    m_TimerWating.start(60000); // спустя минуту попытаемся вновь соедениться с сервером
}

void MyThread::isOnlain(){
    if (m_config.isOnline()){
        m_TimerWating.stop();
        if (m_flag == PointsPay)
            this->getPointsPay(m_pointsPay.count());
        else this->getFullInfo();
    }
}

void MyThread::setServerTime(QString time){
    this->m_serverTime = time;
}

QString MyThread::getPlatform() {
#if defined(Q_OS_WIN)
    return "winxp";
#elif defined(Q_OS_LINUX)
    return "linux";
#elif defined(Q_OS_MACOSX)
    return "macos";
#endif
}

Подскажите,пожалуйста,что я не так делаю???


Название: Re: QNetworkConfigurationManager и QThread
Отправлено: V1KT0P от Апрель 23, 2012, 14:00
Здравствуйте! Ребята, помогите пожалуйста разобраться.
Мне в приложении понадобилось создать 2 класса в которых я создаю объект QNetworkConfigurationManager.
Первый класс авторизуется на сервере, а второй получает данные с сервера. Второй класс является потоком.
Приложение компилируется,но в процессе работы вываливается следующая ошибка:
QObject: Cannot create children for a parent that is in a different thread.
(Parent is QNetworkAccessManager(0x8c8d808), parent's thread is MyThread(0x8da5980), current thread is QThread(0x8a9dfd0)
Я уже кучу статей перечитала как разрешить эту проблему, пересмотрела много примеров на форуме, но мне не помогло.
Привожу код класса потока, так как эта ошибка от него идет:
Код:
#ifndef MYTHREAD_H
#define MYTHREAD_H

#include <QThread>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QTimer>
#include <QNetworkConfigurationManager>
#include <Parser>
#include <Serializer>
#include <QObjectHelper>
#include <QTime>
#include "macroconfig.h"

class MyThread : public QThread
{
    Q_OBJECT
public:
    enum Status{
        PointsPay,
        FullInfo
    };
    explicit MyThread(QObject *parent = 0);
    void getPointsPay(int);
    QString getPlatform() ;
    void setServerTime(QString);
protected:
    void run();
private:
    QString m_skey;
    QNetworkAccessManager *m_manager;
    QNetworkReply *m_reply;
    QNetworkConfigurationManager m_config;
    Status m_flag;
    QTimer m_timer;
    QTimer m_TimerWating;
    QTime m_lastTimeInfo;
    QTime m_lastTimePay;
    QString m_serverTime;
    QString m_os;
    QMap<int,QVariantMap> m_pointsPay;
   
signals:
    QVariantMap succes(QVariantMap);
    QMap<int,QVariantMap> succes(QMap<int,QVariantMap>);
    QString Error(QString);
   
public slots:
        void getFullInfo();
        void finish(QNetworkReply*);
        void Error(QNetworkReply::NetworkError);
        void isOnlain();
        void setParamAndStart(QString skey);
   
};

#endif // MYTHREAD_H


Код:
#include "mythread.h"
#include <QDebug>

MyThread::MyThread(QObject *parent) :
    QThread(parent)
{
    //moveToThread(this);   если раскоментировать то функция run вообще не вызывается....
    m_manager = new QNetworkAccessManager();
    m_manager->moveToThread(this);
    connect(m_manager,SIGNAL(finished(QNetworkReply*)),this,SLOT(finish(QNetworkReply*)));
    connect(&m_TimerWating,SIGNAL(timeout()),this,SLOT(isOnlain()));
    m_lastTimeInfo.addSecs(-60);
    m_lastTimePay.addSecs(-60);
    m_os = this->getPlatform();
    m_timer.setInterval(60000);
}

void MyThread::setParamAndStart(QString skey){  // устанавливаем ключ и запускаем поток
    if (!skey.isEmpty()) {
        m_skey = skey;
        start();   // запускаем поток. Пробовала и из main.cpp но ничего не изменилось
    }
}

void MyThread::run(){
    qDebug()<<"run";
    getPointsPay(1);
    //getFullInfo();
    m_timer.start();
    exec();             // использовать собственную очередь событий
}

void MyThread::getPointsPay(int type){  // поработать с объектом QTime
   qDebug()<<__FUNCTION__<<type;
    m_flag = PointsPay;
    //if (m_lastTimePay.addSecs(30) <= QTime::currentTime()){
        QString Responce = "/?r=client/paymentplacesinfo&place_type_id=%1";
        Responce = HOST + Responce.arg(QString::number(type));
        if (m_config.isOnline()){
            m_lastTimePay = QTime::currentTime();
            m_reply = m_manager->get(QNetworkRequest(Responce));
            m_reply->moveToThread(this);
            m_reply->ignoreSslErrors();
            connect(m_reply,SIGNAL(error(QNetworkReply::NetworkError)),this,SLOT(Error(QNetworkReply::NetworkError)));
        }
        else  m_TimerWating.start(30000);
   // }

}

void MyThread::getFullInfo(){
  m_flag = FullInfo;
  if (m_lastTimePay.addSecs(30) <= QTime::currentTime()){   // проверяем как давно мы запрашивали эту информацию
        QString param = "/?r=client/getfullInfo&skey=%1&platform=%2&date=%3";
        param = HOST+param.arg(m_skey,m_os,m_serverTime);
        if (m_config.isOnline()){
            m_lastTimeInfo = QTime::currentTime();
            m_reply = m_manager->get(QNetworkRequest(param));
            connect(m_reply,SIGNAL(error(QNetworkReply::NetworkError)),this,SLOT(Error(QNetworkReply::NetworkError)));
            m_reply->ignoreSslErrors();
        }
        else  m_TimerWating.start(30000);

   }

}

void MyThread::finish(QNetworkReply* reply){
    QByteArray json = reply->readAll();
    QJson::Parser parser;
    bool ok;
    QVariantMap buffer = parser.parse (json, &ok).toMap();
    if (ok){
        if (m_flag == PointsPay){
            m_pointsPay[buffer["current"].toInt()] = buffer;
            if (buffer["current"].toInt()!=3)
                this->getPointsPay(buffer["current"].toInt()+1); // запрашиваем следующую точку оплаты
            else this->getFullInfo(); // получаем пользовательскую информацию
        }
       else {
            emit succes(buffer);  // возвращаем пользовательскую информацию
            QVariantMap news = buffer["news"].toMap();
            QList<QVariant> created = news.value("created").toList();
            QList<QVariant> modified = news.value("modified").toList();
            QList<QVariant> deleted = news.value("deleted").toList();
            if (created.isEmpty() || modified.isEmpty() || deleted.isEmpty()){
                this->getPointsPay(1);
            }
            m_timer.start();
        }
    }

}

void MyThread::Error(QNetworkReply::NetworkError error){
    switch(error)
       {

       case QNetworkReply::ConnectionRefusedError:{
           emit Error(QString::fromLocal8Bit("Сервер перегружен."));
           break;
       }

       case QNetworkReply::ContentNotFoundError:{
               emit Error(QString::fromLocal8Bit("Ошибка сервера 404."));
               break;
           }
       case QNetworkReply::HostNotFoundError:{
               emit Error( QString::fromLocal8Bit("Не найден удаленный сервер."));
               break;
           }

       default: {
               emit Error(m_reply->errorString());
               break;
           }
       }
    m_TimerWating.start(60000); // спустя минуту попытаемся вновь соедениться с сервером
}

void MyThread::isOnlain(){
    if (m_config.isOnline()){
        m_TimerWating.stop();
        if (m_flag == PointsPay)
            this->getPointsPay(m_pointsPay.count());
        else this->getFullInfo();
    }
}

void MyThread::setServerTime(QString time){
    this->m_serverTime = time;
}

QString MyThread::getPlatform() {
#if defined(Q_OS_WIN)
    return "winxp";
#elif defined(Q_OS_LINUX)
    return "linux";
#elif defined(Q_OS_MACOSX)
    return "macos";
#endif
}

Подскажите,пожалуйста,что я не так делаю???

Твоя проблема в том что надо сперва почитать справку и разобраться с особенностями многопоточного программирования. Тот код который записан в конструкторе выполняется в том потоке в котором вызван а не из того потока который создается. И есть некоторые классы которые нельзя перекидывать из потока в поток. Таким классом является QNetworkAccessManager. Ты его создаешь в конструкторе и он привязывается к тому потоку который создает новый тред. А затем пытаешься его запихать в новый тред. Здесь уже давно говорилось что наследоваться от треда нежелательно, особенно когда не понимаешь что делаешь.


Название: Re: QNetworkConfigurationManager и QThread
Отправлено: Bepec от Апрель 23, 2012, 14:04
ВИКТОР!!! Изыди!

Наследоваться от QThread можно и это решение не имеет никаких отрицательных сторон. Уже разбирали это.

по теме:

Проблема у вас в том, что создавать QNAM(менегер), надо либо в функции run потока, либо использовать moveToThread.

PS к тому же moveToThread вроде никак на run() не может повлиять ;)


Название: Re: QNetworkConfigurationManager и QThread
Отправлено: Igors от Апрель 23, 2012, 14:06
MyThread::MyThread(QObject *parent) :
    QThread(parent)
Уберите parent или подавайте NULL. Раскомментите moveToThread(this);


Название: Re: QNetworkConfigurationManager и QThread
Отправлено: V1KT0P от Апрель 23, 2012, 14:09
ВИКТОР!!! Изыди!
Чего это ты так завелся =).


Название: Re: QNetworkConfigurationManager и QThread
Отправлено: alexis031182 от Апрель 23, 2012, 14:16
Проблема в том, что объект QThread, а соответственно и все переменные и объекты, которые он содержит, принадлежат основному потоку приложения. Но при этом осуществляется попытка создания дочернего объекта в потоке, который реализует QThread.

Я бы посоветовал сменить концепцию использования многопоточности в Вашем приложении, поскольку объект класса QThread не является потоком как таковым, он лишь предоставляет возможность выполнения пользовательских операций в отдельном потоке.

На мой взгляд, использовать многопоточность лучше посредством реализации отдельного класса, не унаследованного от QThread:
Код:
class MyClass : public QObject
{
   Q_OBJECT
signals:
   //Сигнал о завершении работы "void process()"
   void finished();

public:
   //Обращаем внимание, что в конструкторе не указываем родителя,
   //но при этом можем внести какие-либо другие параметры.
   MyClass() : QObject() {}

   virtual ~MyClass() {}

public slots:
   void process() {
      //Здесь наш код, который должен выполниться в отдельном потоке.
      ...

      //Отсылаем сигнал о завершении выполнения.
      emit finished();
   }

private:
   //Здесь указываем наши приватные объекты и переменные.

};
Ну а теперь, собственно метод использования:
Код:
QThread *thread = new QThread;
MyClass *myclass = new MyClass();
myclass->moveToThread(thread);
connect(thread, SIGNAL(started()), myclass, SLOT(process()));
connect(myclass, SIGNAL(finished()), thread, SLOT(quit()));
connect(myclass, SIGNAL(finished()), myclass, SLOT(deleteLater()));
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
thread->start();
Здесь мы создаём объект MyClass, перемещаем его в отдельный поток, и соединяем необходимые к обработке сигналы со слотами. Думаю, что из этого кода очевидна идея.


Название: Re: QNetworkConfigurationManager и QThread
Отправлено: Igors от Апрель 23, 2012, 14:18
И есть некоторые классы которые нельзя перекидывать из потока в поток. Таким классом является QNetworkAccessManager. Ты его создаешь в конструкторе и он привязывается к тому потоку который создает новый тред. А затем пытаешься его запихать в новый тред. Здесь уже давно говорилось что наследоваться от треда нежелательно,
Ну переброс QNetworkAccessManager не имеет отношения к наследованию. Я не работаю с вебом и могу ошибаться, но мне интересно узнать почему QNetworkAccessManager нельзя перекидывать - вроде никаких оснований не видно. Ну хочу чтобы он крутился через eventLoop нитки, почему нельзя?


Название: Re: QNetworkConfigurationManager и QThread
Отправлено: V1KT0P от Апрель 23, 2012, 14:25
И есть некоторые классы которые нельзя перекидывать из потока в поток. Таким классом является QNetworkAccessManager. Ты его создаешь в конструкторе и он привязывается к тому потоку который создает новый тред. А затем пытаешься его запихать в новый тред. Здесь уже давно говорилось что наследоваться от треда нежелательно,
Ну переброс QNetworkAccessManager не имеет отношения к наследованию. Я не работаю с вебом и могу ошибаться, но мне интересно узнать почему QNetworkAccessManager нельзя перекидывать - вроде никаких оснований не видно. Ну хочу чтобы он крутился через eventLoop нитки, почему нельзя?
Ну дык справку почитай:
Цитировать
Changes the thread affinity for this object and its children. The object cannot be moved if it has a parent. Event processing will continue in the targetThread.


Название: Re: QNetworkConfigurationManager и QThread
Отправлено: Igors от Апрель 23, 2012, 14:33
Ну дык справку почитай:
Цитировать
Changes the thread affinity for this object and its children. The object cannot be moved if it has a parent. Event processing will continue in the targetThread.
Мне это известно, так для любого объекта с парентом. А конкретно QNetworkAccessManager данный случай-то здесь причем?
Код
C++ (Qt)
m_manager = new QNetworkAccessManager();
 
Никакого парента я здесь не наблюдаю


Название: Re: QNetworkConfigurationManager и QThread
Отправлено: V1KT0P от Апрель 23, 2012, 14:48
Ну дык справку почитай:
Цитировать
Changes the thread affinity for this object and its children. The object cannot be moved if it has a parent. Event processing will continue in the targetThread.
Мне это известно, так для любого объекта с парентом. А конкретно QNetworkAccessManager данный случай-то здесь причем?
Код
C++ (Qt)
m_manager = new QNetworkAccessManager();
 
Никакого парента я здесь не наблюдаю
Я вот например удаление m_manager не вижу. Если он его вручную не удаляет, значит должен ему родителя назначить.


Название: Re: QNetworkConfigurationManager и QThread
Отправлено: Igors от Апрель 23, 2012, 15:08
Я вот например удаление m_manager не вижу. Если он его вручную не удаляет, значит должен ему родителя назначить.
И что, проблема в деструкторе нитки его удалить? Или подать парентом MyThread. То есть выходит что QNetworkAccessManager можно перекидывать с тем же успехом как и любой др объект. А по-Вашему не так
И есть некоторые классы которые нельзя перекидывать из потока в поток. Таким классом является QNetworkAccessManager.
Чего наводить тень на плетень?  :)



Название: Re: QNetworkConfigurationManager и QThread
Отправлено: V1KT0P от Апрель 23, 2012, 15:13
Я вот например удаление m_manager не вижу. Если он его вручную не удаляет, значит должен ему родителя назначить.
И что, проблема в деструкторе нитки его удалить? Или подать парентом MyThread. То есть выходит что QNetworkAccessManager можно перекидывать с тем же успехом как и любой др объект. А по-Вашему не так
И есть некоторые классы которые нельзя перекидывать из потока в поток. Таким классом является QNetworkAccessManager.
Чего наводить тень на плетень?  :)
Да немного ошибся, бывает. Плохо выспался, голова не так соображает =(.


Название: Re: QNetworkConfigurationManager и QThread
Отправлено: virtual_root от Апрель 23, 2012, 22:29
Ребята, спасибо всем большое!!! Ваши советы помогли разобраться. Очень приятно, что столько откликнулись.


Название: Re: QNetworkConfigurationManager и QThread
Отправлено: Alex_C от Апрель 24, 2012, 08:25
На мой взгляд, использовать многопоточность лучше посредством реализации отдельного класса, не унаследованного от QThread:

Хотелось бы кстати уточнить - а почему? В чем разница наследования QThread от moveToThread. Как мне кажется - это как бы 2 варианта реализации одного и того же в итоге. Просто moveToThread проще что ли в записи, чем класс от QThread наследовать. Или все же есть какие то принципиальные отличия?


Название: Re: QNetworkConfigurationManager и QThread
Отправлено: alexis031182 от Апрель 24, 2012, 10:29
Хотелось бы кстати уточнить - а почему? В чем разница наследования QThread от moveToThread. Как мне кажется - это как бы 2 варианта реализации одного и того же в итоге. Просто moveToThread проще что ли в записи, чем класс от QThread наследовать. Или все же есть какие то принципиальные отличия?
Оба варианта рабочие, однако наследование от QThread идёт врозь с идеологией использования этого класса. QThread - это не поток, а лишь инструмент управления потоком. По сути, в варианте с наследованием мы получаем монстрообразную форму, которая при выполнении программы может привести ко всяким неожиданностям, на вроде указанной в данном топике проблемы.

Не используя наследование, можно не заботиться о многих вещах, в т.ч. и о иерархии отношений объектов класса, выполняющегося в отдельном потоке. Все parent'ы указываем как обычно. И при этом можем легко перемещать выполняющийся класс из главного потока в параллельный и обратно даже в то время, когда оба из них выполняются. Например:
Код:
QThread *thread = new QThread(this); //Сам QThread может иметь parent'а
thread->start();
...
MyClass *myclass = new MyClass();
myclass->moveToThread(thread);
connect(this, SIGNAL(my_signal()), myclass, SLOT(process()));
connect(myclass, SIGNAL(finished()), this, SLOT(my_slot()));
Код:
void MyClass::process() {
   //Здесь наш код, который должен выполниться в отдельном потоке.
   ...

   //Перемещаем объект обратно в главный поток.
   moveToThread(QCoreApplication::instance()->thread());

   //Отсылаем сигнал о завершении выполнения.
   emit finished();
}


Название: Re: QNetworkConfigurationManager и QThread
Отправлено: Igors от Апрель 24, 2012, 11:05
Хотелось бы кстати уточнить - а почему? В чем разница наследования QThread от moveToThread. Как мне кажется - это как бы 2 варианта реализации одного и того же в итоге. Просто moveToThread проще что ли в записи, чем класс от QThread наследовать. Или все же есть какие то принципиальные отличия?
Просто "так пишут" (в статьях и.т.п) - и многие считают хорошим тоном этому следовать

Оба варианта рабочие, однако наследование от QThread идёт врозь с идеологией использования этого класса. QThread - это не поток, а лишь инструмент управления потоком. По сути, в варианте с наследованием мы получаем монстрообразную форму, которая при выполнении программы может привести ко всяким неожиданностям, на вроде указанной в данном топике проблемы.

Не используя наследование, можно не заботиться о многих вещах, в т.ч. и о иерархии отношений объектов класса, выполняющегося в отдельном потоке. Все parent'ы указываем как обычно. И при этом можем легко перемещать выполняющийся класс из главного потока в параллельный и обратно даже в то время, когда оба из них выполняются. Например:
А чего же в в приводимом Вами примере MyClass создается с parent = NULL? Видимо потому что иначе его не переместить безболезненно, точно так же как и в первом посте. Не видно чем наследование виновато. Да, оно необязательно, а может и не нужно, но никаких монстров и проблем оно не создает.

Чужие мысли могут выглядеть очень красиво (в отличие от своих, корявых) - но они всегда останутся чужими  :)



Название: Re: QNetworkConfigurationManager и QThread
Отправлено: alexis031182 от Апрель 24, 2012, 11:29
Просто "так пишут" (в статьях и.т.п) - и многие считают хорошим тоном этому следовать
Конечно пишут, в т.ч. и в справке Qt (https://qt-project.org/doc/qt-4.8/qthread.html) (крутим страницу вниз до конца). Но определяющим фактором к использованию альтернативного метода, конечно же, должно быть не наличие подобных рекомендаций на официальной странице, а понимание того, что в каждом конкретном случае является наиболее подходящим.

А чего же в в приводимом Вами примере MyClass создается с parent = NULL?
Это основное неприкасаемое условие к перемещаемому объекту.

Видимо потому что иначе его не переместить безболезненно, точно так же как и в первом посте. Не видно чем наследование виновато.
Да ничем не виновато. Просто есть объект-инструмент, а есть объект, над которым этот инструмент производит действие. Мешать одно с другим, получается, вроде как не логично.

Да, оно необязательно, а может и не нужно, но никаких монстров и проблем оно не создает.
Подобной проблемы, что возникла у ТС не появилось бы в случае неиспользования наследования.

Чужие мысли могут выглядеть очень красиво (в отличие от своих, корявых) - но они всегда останутся чужими  :)
А это вообще непонятно к чему сказано. Я где-то указывал авторство к приводимому коду?


Название: Re: QNetworkConfigurationManager и QThread
Отправлено: Igors от Апрель 24, 2012, 12:28
Просто есть объект-инструмент, а есть объект, над которым этот инструмент производит действие. Мешать одно с другим, получается, вроде как не логично.
В Вашем примере неясно зачем городить еще и MyClass если можно спокойно разместить данные в наследнике QThread. Мол, парента может иметь - несерьезно, это не UI и роль парента невелика (если не ноль). К тому же MyClass все равно без парента.

Я бы попробовал обосновать так: а почему мы считаем что функциональность должна обязательно выполняться в отдельной нитке? А вдруг нам надо перенести этот функционал в главную? Или в др нитку которая еще что-то выполняет? Тогда мы никак не выкрутимся если унаследовались от QThread.

И вообще можно просто и честно сказать: "ото написано, наверное не дураки писали. Перепроверять и думать - оно мне надо? Проще воспользоваться, тем более это легко". Не вижу ничего плохого в этом (пусть утилитарном) подходе. Сплошь и рядом всем так приходится так делать - иначе просто не выплыть "в бурном информационном потоке".


Название: Re: QNetworkConfigurationManager и QThread
Отправлено: alexis031182 от Апрель 24, 2012, 12:56
В Вашем примере неясно зачем городить еще и MyClass если можно спокойно разместить данные в наследнике QThread.
Что значит "городить ещё"? Размер кода по сути тот же: что наследуем QThread - создаём новый класс, что идём по другому пути - то же самое (ну разве что пара строк на connect).

И да, можно спокойно разместить данные в наследнике QThread, кто же против :)

Мол, парента может иметь - несерьезно, это не UI и роль парента невелика (если не ноль). К тому же MyClass все равно без парента.
Не очень понял :)

Я бы попробовал обосновать так: а почему мы считаем что функциональность должна обязательно выполняться в отдельной нитке? А вдруг нам надо перенести этот функционал в главную? Или в др нитку которая еще что-то выполняет? Тогда мы никак не выкрутимся если унаследовались от QThread.
Это побочная/параллельная/дополнительная ситуация. Я не стал её приводить как аргумент, поскольку такое в основном редко необходимо, да и к вопросу ТС очевидно не имеет отношения.

И вообще можно просто и честно сказать: "ото написано, наверное не дураки писали. Перепроверять и думать - оно мне надо? Проще воспользоваться, тем более это легко". Не вижу ничего плохого в этом (пусть утилитарном) подходе. Сплошь и рядом всем так приходится так делать - иначе просто не выплыть "в бурном информационном потоке".
Igors, не ведаю, с чего Вы вдруг взяли на себя это тяжёлое бремя выводить всех и каждого (либо по какой-то причине только меня) на чистую воду, однако могу всецело Вас заверить, что не имею отношения к тому подтексту, что так настойчиво Вами копируется из поста в пост.


Название: Re: QNetworkConfigurationManager и QThread
Отправлено: Bepec от Апрель 24, 2012, 13:54
Насчёт наследования и moveToThread - скажу проще:

1) наследник от QThread и moveToThread(this) в конструкторе
2) свой класс и moveToThread(поток) в своих классах

1) позволяет избежать десятков проблем на мелких проектах, исчезает необходимость в "распределении объектов" по потокам. Да и впоследствии нет нужды искать - где же ты кинул класс в поток и как.

2) позволяет распределять нагрузку на потоки, в больших проектах. Или же когда набор действий, выполняемых в другом потоке, не является постоянным. Переменные, которые указываются пользователем, к примеру, и действия с ними.


Оба способа равнозначны, но я использую 1.

Почему?

Потому что я создаю максимум 1-2 потока в программе. И если появляется необходимость переноса функционала (а она возникает очень часто), то достаточно просто подключить 2 файлика в проект и прописать параметры в конструктор.

Второй способ я не использую, ибо не встречал ещё настолько серьёзного проекта.
 
PS первый способ короче, понятнее для "чужого" программиста.
Второй способ длиннее, непонятнее, но более гибкий в рамках больших задач.

А нужна ли вам его гибкость? :P