Название: 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 Код: #include "mythread.h" Подскажите,пожалуйста,что я не так делаю??? Название: Re: QNetworkConfigurationManager и QThread Отправлено: V1KT0P от Апрель 23, 2012, 14:00 Здравствуйте! Ребята, помогите пожалуйста разобраться. Твоя проблема в том что надо сперва почитать справку и разобраться с особенностями многопоточного программирования. Тот код который записан в конструкторе выполняется в том потоке в котором вызван а не из того потока который создается. И есть некоторые классы которые нельзя перекидывать из потока в поток. Таким классом является QNetworkAccessManager. Ты его создаешь в конструкторе и он привязывается к тому потоку который создает новый тред. А затем пытаешься его запихать в новый тред. Здесь уже давно говорилось что наследоваться от треда нежелательно, особенно когда не понимаешь что делаешь.Мне в приложении понадобилось создать 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 Код: #include "mythread.h" Подскажите,пожалуйста,что я не так делаю??? Название: 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) : Уберите parent или подавайте NULL. Раскомментите moveToThread(this);QThread(parent) Название: Re: QNetworkConfigurationManager и QThread Отправлено: V1KT0P от Апрель 23, 2012, 14:09 ВИКТОР!!! Изыди! Чего это ты так завелся =).Название: Re: QNetworkConfigurationManager и QThread Отправлено: alexis031182 от Апрель 23, 2012, 14:16 Проблема в том, что объект QThread, а соответственно и все переменные и объекты, которые он содержит, принадлежат основному потоку приложения. Но при этом осуществляется попытка создания дочернего объекта в потоке, который реализует QThread.
Я бы посоветовал сменить концепцию использования многопоточности в Вашем приложении, поскольку объект класса QThread не является потоком как таковым, он лишь предоставляет возможность выполнения пользовательских операций в отдельном потоке. На мой взгляд, использовать многопоточность лучше посредством реализации отдельного класса, не унаследованного от QThread: Код: class MyClass : public QObject Код: QThread *thread = new QThread; Название: 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 Ну дык справку почитай: Мне это известно, так для любого объекта с парентом. А конкретно QNetworkAccessManager данный случай-то здесь причем?Цитировать 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 Отправлено: V1KT0P от Апрель 23, 2012, 14:48 Ну дык справку почитай: Мне это известно, так для любого объекта с парентом. А конкретно QNetworkAccessManager данный случай-то здесь причем?Цитировать 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, 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'а Код: void MyClass::process() { Название: Re: QNetworkConfigurationManager и QThread Отправлено: Igors от Апрель 24, 2012, 11:05 Хотелось бы кстати уточнить - а почему? В чем разница наследования QThread от moveToThread. Как мне кажется - это как бы 2 варианта реализации одного и того же в итоге. Просто moveToThread проще что ли в записи, чем класс от QThread наследовать. Или все же есть какие то принципиальные отличия? Просто "так пишут" (в статьях и.т.п) - и многие считают хорошим тоном этому следовать Оба варианта рабочие, однако наследование от QThread идёт врозь с идеологией использования этого класса. QThread - это не поток, а лишь инструмент управления потоком. По сути, в варианте с наследованием мы получаем монстрообразную форму, которая при выполнении программы может привести ко всяким неожиданностям, на вроде указанной в данном топике проблемы. А чего же в в приводимом Вами примере MyClass создается с parent = NULL? Видимо потому что иначе его не переместить безболезненно, точно так же как и в первом посте. Не видно чем наследование виновато. Да, оно необязательно, а может и не нужно, но никаких монстров и проблем оно не создает.Не используя наследование, можно не заботиться о многих вещах, в т.ч. и о иерархии отношений объектов класса, выполняющегося в отдельном потоке. Все parent'ы указываем как обычно. И при этом можем легко перемещать выполняющийся класс из главного потока в параллельный и обратно даже в то время, когда оба из них выполняются. Например: Чужие мысли могут выглядеть очень красиво (в отличие от своих, корявых) - но они всегда останутся чужими :) Название: 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 |