Russian Qt Forum
Ноябрь 23, 2024, 08:51
Добро пожаловать,
Гость
. Пожалуйста,
войдите
или
зарегистрируйтесь
.
Вам не пришло
письмо с кодом активации?
1 час
1 день
1 неделя
1 месяц
Навсегда
Войти
Начало
Форум
WIKI (Вики)
FAQ
Помощь
Поиск
Войти
Регистрация
Russian Qt Forum
>
Forum
>
Qt
>
Многопоточное программирование, процессы
>
MoveToThread (все-таки хочется понять ..)
Страниц: [
1
]
2
3
...
5
Вниз
« предыдущая тема
следующая тема »
Печать
Автор
Тема: MoveToThread (все-таки хочется понять ..) (Прочитано 47913 раз)
Igors
Джедай : наставник для всех
Offline
Сообщений: 11445
MoveToThread (все-таки хочется понять ..)
«
:
Март 20, 2012, 13:01 »
Добрый день
Просматривал статейку
http://habrahabr.ru/post/115835/
.
Цитировать
Решение, которое очень часто предлагают на форумах и блогах – добавить в конструктор Thread команду moveToThread(this):
class Thread : public QThread {
Q_OBJECT
public:
Thread() {
moveToThread(this); // WRONG
}
/* ... */
};
которое действительно поможет (потому что принадлежность объекта Thread изменится), но это очень плохое решение. Что же плохого тут? Да то, что мы недопонимаем назначения объекта потока (потомков QThread): объекты QThread – это не потоки; они всего лишь объекты для управления потоками, которые используются в другом потоке (обычно, в котором они находятся).
Аргументация чисто "на понтах" - мол, "недопонимаем" но вот чего?
Мы хотим чтобы сигналы (посланные Thread) принимались в eventLoop этой нитки, moveToThread это обеспечит. Далее в этой статье говорится что нужно мувать объекты в нитку. Ясно это тоже будет работать, но чем же плохо переместить (изменить принадлежность) объекта Thread ?
Эта тема часто мелькает тут и там,
Авварон
объяснял но я лично не понял (туповат). Попробуем начать "от печки" - чем так (wrong выше) плохо? Где/как это может заклинить? На живом простом примере, а не сваливаться в обезьянничанье (типа "а вот там напысано!!!"). В конце-концов не все что пишут - правда
Спасибо
Записан
Авварон
Джедай : наставник для всех
Offline
Сообщений: 3260
Re: MoveToThread (все-таки хочется понять ..)
«
Ответ #1 :
Март 20, 2012, 13:23 »
Цитата: Igors от Март 20, 2012, 13:01
Добрый день
Просматривал статейку
http://habrahabr.ru/post/115835/
.
Цитировать
Решение, которое очень часто предлагают на форумах и блогах – добавить в конструктор Thread команду moveToThread(this):
class Thread : public QThread {
Q_OBJECT
public:
Thread() {
moveToThread(this); // WRONG
}
/* ... */
};
которое действительно поможет (потому что принадлежность объекта Thread изменится), но это очень плохое решение. Что же плохого тут? Да то, что мы недопонимаем назначения объекта потока (потомков QThread): объекты QThread – это не потоки; они всего лишь объекты для управления потоками, которые используются в другом потоке (обычно, в котором они находятся).
Аргументация чисто "на понтах" - мол, "недопонимаем" но вот чего?
Мы хотим чтобы сигналы (посланные Thread) принимались в eventLoop этой нитки, moveToThread это обеспечит. Далее в этой статье говорится что нужно мувать объекты в нитку. Ясно это тоже будет работать, но чем же плохо переместить (изменить принадлежность) объекта Thread ?
Эта тема часто мелькает тут и там,
Авварон
объяснял но я лично не понял (туповат). Попробуем начать "от печки" - чем так (wrong выше) плохо? Где/как это может заклинить? На живом простом примере, а не сваливаться в обезьянничанье (типа "а вот там напысано!!!"). В конце-концов не все что пишут - правда
Спасибо
Ну тут 2 вопроса - одно действительно люди недопонимают (не мы с вами) когда нужно, а когда не нужно использовать мув ту тред от самого треда. Есть задачи, в которых это будет проще написать (чем делать пару тред + объект-воркер) - когда надо к примеру перед вызовом exec() в треде сделать немного инити - для этого надо сабклассить тред. И раз уж мы отсаклассили его, то и слоты проще написать в нем, чем создавать еще и класс-воркер со слотами.
А второй вопрос "чистоты" архитектуры - тред задуман как КОНТЕЙНЕР для потока, место, где разрываются связи парент/чайлд и начинается полностью новый конктекст - ведь QObject не может иметь парентом объект в другом треде. И тред получается "мостом" между двумя иерархиями объектов - в родительском потоке и в дочернем. При этом сам тред принадежит родительскому потоку - тк именно он "должен" знать когда стартовать/стопать и удалять тред. И получается не очень логично - мы создаем и удаляем тред из родительского потока, а метод thread() с этим потоком не совпадает. Как-то так, извиняюсь за сумбурность:)
Записан
Igors
Джедай : наставник для всех
Offline
Сообщений: 11445
Re: MoveToThread (все-таки хочется понять ..)
«
Ответ #2 :
Март 20, 2012, 13:27 »
Цитата: mutineer от Март 20, 2012, 13:05
На живом простом примере написано тут
http://labs.qt.nokia.com/2010/06/17/youre-doing-it-wrong/
И эту статью я читал, думаю и др тоже. С архитектурными соображениями (мол, здесь логичнее агрегат вместо наследования) вполне согласен. Но техническая ошибка-то где?
Цитата: mutineer от Март 20, 2012, 13:05
Если конкретно - класс QThread не спроектирован как потокобезопасный, поэтому вызов его методов (start, terminate, wait, etc) из основного потока, когда сам объект живет сам в себе, может закончиться плохо. А может и не закончиться - как повезет
Каким образом? Если я вызываю start/wait из 2 и более ниток? Ну так я всегда получу по ушам, moveToThread здесь ни при чем
Цитата: mutineer от Март 20, 2012, 13:05
Но это только ИМХО автора статьи, ибо проблемы многопоточности очень ускользающи и придумать пример, когда это 100% приведет к проблемам, практически невозможно
Засомневались - уже хорошо
Записан
Bepec
Гость
Re: MoveToThread (все-таки хочется понять ..)
«
Ответ #3 :
Март 20, 2012, 13:28 »
Просили же не воды, а камня!!!
Почитал статейку...
Цитировать
People show their code, or examples based on their code, and I often end up thinking:
You’re doing it wrong
Уже весело. (далее замечу, что автор в конце уточняет, что это нифига не правильное решение, нифига не рекомендуемое решение, а просто его мнение...)
А уж дальнейшие рассуждения...
Конечно же он не был спроектирован как класс для moveToThread.
Но он имеет все возможности для этого, как и любой унаследованный от QObject. Не лучше, не хуже. Хоть создай свой с 0, хоть moveToThread(this) сделай.
Мы имеем возможность(документированную).
Мы хотим этого(агась, так точно).
К чему плохому это приведёт? Только к рабочему коду!(то, что я унаследуюсь от Q***** любого объекта не испортит многопоточности, не? Или каждый QWidget будет в гробу вертеться?)
И наконец уверяют - создайте другой класс И... сделайте moveToThread()...
Смысл? Будет то же самое, вид сбоку, правда будет ещё головная боль с родителями.
- (тот же QNetworkAcessManager, если его создать отдельным классом в главной нитке, не даст себя переместить в дополнительную)
Уверяют - этот же класс можно будет упрятать и в другой поток, и вообще это гуд... А мне НУЖЕН класс, работающий в собственной нитке и не с кем не делящей её.
PS а так вся шебурха по этому поводу - бред помоему.
upd: Конечно есть шанс, что это приведёт в дальнейшем, в 0,000001% случаев к краху нитки и порче программе, НО. До этого сотни тысяч раз крах и порча случится по моей(да и любого) вине. Изза архитектуры/переменных/чужого кода/мутексов. Даже чужая программа может спокойно повредить любые данные внутри программы с тем же шансом, если не больше. Таки что же делать - тройное копирование, контроль доступа к памяти и вуаля - собственная операционная система?
upd to Авварон:
Я вот незнаю какой выигрыш от одного класса в потоке. И вы что-то об этом не пишите
Таки откуда ж я узнаю(если не учитывать телепатию и вмешательство инопланетян)
Вопрос чистоты - ты используешь контейнеры для хранения контейнеров? Класс для хранения классов? Контейнер для хранения структур для хранения классов?
Таки он и остаётся контейнером.
Ты не удаляешь его, указатель на него остаётся, связь то не теряется.
PS и ради интереса - зачем так сказать в программе может пригодится thread нити и знание её родителя?
Записан
mutineer
Гость
Re: MoveToThread (все-таки хочется понять ..)
«
Ответ #4 :
Март 20, 2012, 13:33 »
Писать в тред было ошибкой с моей стороны - удалил. Бессмысленный флейм это. Мне не сложно неиспользовать moveToThread(this) ибо от неиспользования этой конструкции вреда точно не будет. Видимо вам всем сложно от нее отказаться (иначе не было бы вопроса) - ваше право
Записан
Странник
Гость
Re: MoveToThread (все-таки хочется понять ..)
«
Ответ #5 :
Март 20, 2012, 13:37 »
зачем объект QThread помещать в поток, которым он же управляет - непонятно. пользы не вижу, проблем достаточно. как минимум придется обеспечить потокобезопасность и учесть, что цикл обработки событий потока будет запущен после создания объекта QThread и завершится до его уничтожения.
Записан
V1KT0P
Гость
Re: MoveToThread (все-таки хочется понять ..)
«
Ответ #6 :
Март 20, 2012, 13:47 »
Цитата: Странник от Март 20, 2012, 13:37
зачем объект QThread помещать в поток, которым он же управляет - непонятно. пользы не вижу, проблем достаточно. как минимум придется обеспечить потокобезопасность и учесть, что цикл обработки событий потока будет запущен после создания объекта QThread и завершится до его уничтожения.
Если ты про moveToThread, то это нужно чтоб все сигналы выполнялись в его контексте. Я сам на такое напоролся, и сервак за неделю два раза из-за этого падал. Если бы я сразу вместо наследования от QThread, просто переносил обработчик событий объектов в него этого бы не случилось. И то я про это узнал чисто случайно.
Записан
Авварон
Джедай : наставник для всех
Offline
Сообщений: 3260
Re: MoveToThread (все-таки хочется понять ..)
«
Ответ #7 :
Март 20, 2012, 13:52 »
Цитата: Bepec от Март 20, 2012, 13:28
Мы имеем возможность(документированную).
Мы хотим этого(агась, так точно).
К чему плохому это приведёт? Только к рабочему коду!(то, что я унаследуюсь от Q***** любого объекта не испортит многопоточности, не? Или каждый QWidget будет в гробу вертеться?)
И наконец уверяют - создайте другой класс И... сделайте moveToThread()...
Документация по треду безнадежно устарела, тк была написана в то время, когда у треда run() был чисто виртуальный и НЕ вызывал exec.
Статья лишь говорит о том, что сменилась парадигма использования тредов (что не отражено в документации _ну воообще никак_) - вместо чтоб сабклассить тред делать воркеры, тк это "более кутешно"- вы можете делать несколько воркеров в 1м треде, вы можете делать несколько тредов с воркерами и с сигнал-слотами это вам ничего не стоит. Побуду кэпом - если у вас встанет задача переиспользования ниток, то с сабклассингом вы ничего сделать не сможете - вам придется удалять класс треда и писать воркеров. Не проще сразу написать "как правильно"?
А с КуНАМом это косяк кутешников, но непонятно напуркуа его создавать в треде, есди он и так создает мильен тредов внутри себя и весь асинхронный? Нет, ну конечно парсинг приходящих данных в глав потоке будет тормозить, но зачем так делать? Передавайте прочтенную дату в тред на обработку...
Записан
Bepec
Гость
Re: MoveToThread (все-таки хочется понять ..)
«
Ответ #8 :
Март 20, 2012, 13:56 »
Странник, ты же вумный - поясни в чём "плохость данного метода". И да, можно конкретики аля "делаем вот так, падает допустим через 4 часа".
to В1ктор - ты уверен, что именно из-за ээтого падал, а не из-за качества твоего кода и понимания того, что ты делаешь? Могу ошибаться , заранее прощения прошу, но не в той ли ты теме отписался аля "переписал по новому без moveToThread - заработало"? Я тож когда программу переписываю у меня всё работает Оо... Особенно когда вместо неправильного, правильное пишу
PS А если есть примерчик нестабильной работы из-за moveToThread(), то выложи плз.?
update to Авварон - Я собственно и спрашиваю - мне нужен поток-воркер(адын, который будет создаваться n раз). Зачем мне писать воркер + нить.
И таки да - Вопрос то стоит, чем это плохо? Где может заклинить? (Амбэ ситуации аля "придётся потом архитектуру перекраивать" опустите пожалуйста).
«
Последнее редактирование: Март 20, 2012, 13:57 от Bepec
»
Записан
LisandreL
Птица говорун
Offline
Сообщений: 984
Надо улыбаться
Re: MoveToThread (все-таки хочется понять ..)
«
Ответ #9 :
Март 20, 2012, 14:00 »
Проблемы будут как минимум с удалением потока (причём в релизной и дебажной версии работа может отличаться).
Наследники QObject'а не любят, когда их удаляют не из их потока.
То есть у нас варианты:
1) сделать delete this; в конце run()
При этом надо думать о том, что бы по указателю не обратиться к уже самоудалённому потоку и т.п.
2) сделать moveToThread( X ); в конце run отправив поток умирать другой поток (заведом живой на этом цикле работы программы). Если программа отключается то это так же может быть проблематичным.
Записан
V1KT0P
Гость
Re: MoveToThread (все-таки хочется понять ..)
«
Ответ #10 :
Март 20, 2012, 14:03 »
Цитата: Bepec от Март 20, 2012, 13:56
to В1ктор - ты уверен, что именно из-за ээтого падал, а не из-за качества твоего кода и понимания того, что ты делаешь? Могу ошибаться , заранее прощения прошу, но не в той ли ты теме отписался аля "переписал по новому без moveToThread - заработало"? Я тож когда программу переписываю у меня всё работает Оо... Особенно когда вместо неправильного, правильное пишу
Точно, сервер сам по себе простой, но там потоки общаются с общими данными, так вот из-за того что я наследовался от треда и не мувил его сам в себя обработчик слотов запускался не оттуда откуда я ожидал. У меня все было построено так что к данным в потоке напрямую из другого потока нельзя изменить. Оказалось что я неправильно сделал и некоторые функции выполнялись не из того потока, что иногда приводит к порче данных и падению сервера. Добавил везде мувы сами в себя и уже вторую неделю стабильно работает. Короче щас пойду поем и попробую сделать пример.
Записан
Bepec
Гость
Re: MoveToThread (все-таки хочется понять ..)
«
Ответ #11 :
Март 20, 2012, 14:05 »
Я могу ошибаться конечно, но разве при правильном завершении секции run() поток не умирает?
Во всяком случае в "живых" его впоследствии не наблюдается(дебагер вроде врать не должен, не?).
PS при завершении работы выдрать паузу на завершение потоков можно вполне. А от reset() спасёт только молитва Ктулху.
to V1ктор, помоему вы только что сказали, что проблема была в вашей архитектуре, не?
Записан
Igors
Джедай : наставник для всех
Offline
Сообщений: 11445
Re: MoveToThread (все-таки хочется понять ..)
«
Ответ #12 :
Март 20, 2012, 14:08 »
Давайте попробуем как-то "организоваться"
1) Итак, простецкий пример
Цитировать
class Thread : public QThread {
Q_OBJECT
public:
Thread() {
moveToThread(this); // dusk but not wrong ;-)
}
/* ... */
};
технически
ничем не плох и ни к каким крашам не приведет. Так ли это? (мое мнение что так)
2) Др дело это может быть неудачным архитектурным решением - это тоже интересно обсудить, но сначала закончим с 1 а то будем прыгать туда-сюда
Спасибо
Записан
BRE
Гость
Re: MoveToThread (все-таки хочется понять ..)
«
Ответ #13 :
Март 20, 2012, 14:12 »
Цитата: Igors от Март 20, 2012, 14:08
технически
ничем не плох и ни к каким крашам не приведет. Так ли это? (мое мнение что так)
Ничем не плох. Все будет работать.
Как говаривал профессор Преображенский: "Никогда не читайте перед обедом советских газет."
С точки зрения архитектуры, IMHO, лучше относится к QThread как в "управляльщику" потока, а не как к потоку.
«
Последнее редактирование: Март 20, 2012, 14:14 от BRE
»
Записан
LisandreL
Птица говорун
Offline
Сообщений: 984
Надо улыбаться
Re: MoveToThread (все-таки хочется понять ..)
«
Ответ #14 :
Март 20, 2012, 14:14 »
Igors
,
BRE
а с удалением то что и как?
Записан
Страниц: [
1
]
2
3
...
5
Вверх
Печать
« предыдущая тема
следующая тема »
Перейти в:
Пожалуйста, выберите назначение:
-----------------------------
Qt
-----------------------------
=> Вопросы новичков
=> Уроки и статьи
=> Установка, сборка, отладка, тестирование
=> Общие вопросы
=> Пользовательский интерфейс (GUI)
=> Qt Quick
=> Model-View (MV)
=> Базы данных
=> Работа с сетью
=> Многопоточное программирование, процессы
=> Мультимедиа
=> 2D и 3D графика
=> OpenGL
=> Печать
=> Интернационализация, локализация
=> QSS
=> XML
=> Qt Script, QtWebKit
=> ActiveX
=> Qt Embedded
=> Дополнительные компоненты
=> Кладовая готовых решений
=> Вклад сообщества в Qt
=> Qt-инструментарий
-----------------------------
Программирование
-----------------------------
=> Общий
=> С/C++
=> Python
=> Алгоритмы
=> Базы данных
=> Разработка игр
-----------------------------
Компиляторы и платформы
-----------------------------
=> Linux
=> Windows
=> Mac OS X
=> Компиляторы
===> Visual C++
-----------------------------
Разное
-----------------------------
=> Новости
===> Новости Qt сообщества
===> Новости IT сферы
=> Говорилка
=> Юмор
=> Объявления
Загружается...