![]() |
|
|
![]()
|
|
| null56 |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 721 Регистрация: 19.3.2008 Репутация: 6 Всего: 12 |
Не могу до конца понять назначение это фукнции, особенно ее подтекст NOT THREAD SAFE.
У меня задача состоит в следующем 1) Есть порожденная нить (несколько на самом деле), работает в своем eventloop 2) Один поток, основной управляющий сервер, который создает сокеты и перемещает их в матрицу нитей То есть на псевдокоде это будет выглядеть вот так:
Вопросы 1) Нужно ли делать moveToThread для QSslSocket? 2) Что мне даст функция moveToThread? 3) В описании, что подразумевается под поточно НЕ безопасная? |
|||
|
||||
| SABROG |
|
|||
![]() Hacker ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 2481 Регистрация: 18.9.2006 Репутация: 81 Всего: 91 |
Тут такая система. Если ты создаешь QThread в главном event loop'e, то QThread становится ребенком главного потока (он все-таки QObject), и все слоты и методы выполняются в главном потоке (конструктор в том же числе), кроме метода run(). Все объекты созданные в run() уже дети отдельного - нового потока.
Предположим, что ты захотел наладить систему сообщений между GUI и потоком. Аля нажал на кнопочку и в потоке запустился долгоиграющий процесс. И у тебя ничего не получится, т.к. и GUI и нить - детки главного потока. Это приведет к зависанию GUI до того момента, пока слот нити не вернет управление. В тоже время, если коннектить сигналы к объектам созданных в run()'е, то слоты этих объектов уже будут выполняться в новом потоке. Так вот moveToThread был создан для того, чтобы перенести объект в другой поток, чтобы для объектов, детишек этого потока существовал личный eventLoop со своими сигналами и эвентами. Кроме того у переносимого объекта не должно быть родителей. Насчет thread safe я сам до конца понять не могу, может ты поймешь, посмотри в ассистенте "Reentrancy and Thread-Safety". |
|||
|
||||
| null56 |
|
||||||||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 721 Регистрация: 19.3.2008 Репутация: 6 Всего: 12 |
Отлично, спасибо.. так намного понятнее
У меня ситуация такая, что QSslSocket создается в основном потоке, а я хочу, чтобы слоты обрабатывались в дочернем порожденым, получается мне надо будет сделать sslsocket->moveToThread и в качестве аргумента передать объект класса QThread или как... ? Просто вот тут и пишут про небезопасность межнетевых связях
попробую перевезти суть... Функция ните небезопасна. Текущая нить должна быть такой же как и нитевая строение (связь, на основании связей... хз) иными словами функция может только класть объект из текущей нити для того, чтобы положить в другую, но не может вытащить объект из любой другой нити, чтобы вставить в текущую Код должен быть примерно таким?
И второй момент, если объект у меня был ранее связан с некоторым родителей, то я должен сам разорвать эту связь? setParent(0);...? Добавлено через 5 минут и 2 секунды нет, наверное правильнее будет??/
Добавлено через 7 минут и 59 секунд не... вот так наверное
это же функция, которая вернет дочеринй поток класса QThread |
||||||||
|
|||||||||
| null56 |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 721 Регистрация: 19.3.2008 Репутация: 6 Всего: 12 |
не... так вообще можно получить адрес потока, который был запущен в run или нет?
|
|||
|
||||
| SABROG |
|
|||
![]() Hacker ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 2481 Регистрация: 18.9.2006 Репутация: 81 Всего: 91 |
Я подобные вещи не проделывал. Попробуй и &my_thread передавай и setParent(0) ставь.
В принципе moveToThread можно вызвать в конструкторе новой QThread. Это сообщение отредактировал(а) SABROG - 22.12.2008, 18:30 |
|||
|
||||
| null56 |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 721 Регистрация: 19.3.2008 Репутация: 6 Всего: 12 |
Я попробую.
В конструкторе уже не получится, у меня потоки создаются при запуске программы и их определенное количество, они обслуживают матрицу сокетов.... Надо подумать, а главное поиграться, чтобы знать точно. У потока же есть идентификатор? или что - то там похожее, чтобы в обработке события точно знаТЬ. что за поток. Ну если не получится, то тогда другим путем можно сделать, чтобы проходя по матрице сокетов, поток узнавал готовые к выполнению ячейки и сам добавлял их к себе... Завтра на работе посиотрю и отпишусь |
|||
|
||||
| null56 |
|
||||||||||||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 721 Регистрация: 19.3.2008 Репутация: 6 Всего: 12 |
В общем ситуация такая, это проверено фактами и хочу показать на примере, отсюда и ответ на предудущий мой пост, как заставить выполняться слоты во вторичных потоках...
В качестве примера я приведу 2 класса и файлик main.cpp, для определения выполняющего потока я использовал статическую функцию
для вывода в консоль адреса потока, который у меня не изменяется и так опишу первый посредственный класс, он не меняется и имеет всего один метод, который генерит свой же сигнал my_signal()
Класс для потока не изменяется, лишь его функция run()
Функция run проста
Так вот изменяя различные варианты: создание переменной типа test_thread, хоть в основном евенте, хоть в дочерних, соединяя сигналы где угодно.... ЕСЛИ НЕ СДЕЛАЕШЬ: ServiceThread my_thread.moveToThread(&my_thread); выполянться все будет в основном евенте. То есть эта функция ключевая Вот пример мейна, где все делается в основной функции
Вывод в консоль получился следующим
Хочу заметить, что первый раз сигнал генериться до запуска функции start |
||||||||||||
|
|||||||||||||
| SABROG |
|
|||
![]() Hacker ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 2481 Регистрация: 18.9.2006 Репутация: 81 Всего: 91 |
А создай test_thread внутри метода ServiceThread::run() и попробуй без moveToThread. Это сообщение отредактировал(а) SABROG - 23.12.2008, 20:16 |
|||
|
||||
| null56 |
|
||||||||||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 721 Регистрация: 19.3.2008 Репутация: 6 Всего: 12 |
Пожалуйста
Функция run()
Функция main
Вывод в консоль
Все как вы и писали, конструктор и слоты объекта thread объявлены в главном цикле, а значит там и будут выполняться. В основной функции я вызываю функция start, в запущенной функции run создается объект test и соединяется с сигналами, затем основная ветвь спит и ее евентлуп не может обработать слоты, в то время как в ран сам запускает в очередь еще один сигнал номер 3, но он оказывается раньше, чем 1 и 2. Все ждут, пока первичная нить проснется, когда просыпается, выполняет слоты в порядке поступления сигналов... Если мы хотим, чтобы сигналы их основного потока были первыми, то добавим слово
в функцию run после строчки, где идет коннект сигналов со слотами... и тогда сигналы из первичного потока обгонят сигнал из вторичного Что и видно из
Если я нигде не ошибся, то такое разделение и есть в qt.... как ты и писал выше |
||||||||||
|
|||||||||||
| SABROG |
|
|||
![]() Hacker ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 2481 Регистрация: 18.9.2006 Репутация: 81 Всего: 91 |
Если честно, у меня в голове сейчас полная каша. Так вариант без moveToThread возможен в твоей программе или нет ? Судя по тому, что я вижу eventloop потока отрабатывает как надо, отдельно от главного потока, что и требовалось сделать.
|
|||
|
||||
| null56 |
|
||||||||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 721 Регистрация: 19.3.2008 Репутация: 6 Всего: 12 |
Для моей программы именно он и нужен....
Ну как же правильно? Первичный поток имеет адрес
он же и обрабатывает то, что создается в run()
все слоты вызываются первичным потоком
вторичный поток только создает объект и соединяет сигналы со слотами, но слоты НЕ обрабатывает... вот так получается... Не забивай голову перед сном... лучше отдохни... затвра прочнтешь, если будет желание... Добавлено через 2 минуты и 51 секунду спасибо большое, что помог разобраться |
||||||||
|
|||||||||
| SABROG |
|
|||
![]() Hacker ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 2481 Регистрация: 18.9.2006 Репутация: 81 Всего: 91 |
Что-то тут не так. Закомментированный
в run() должен запускать QEventLoop потока, который и должен, по-хорошему, вызывать слоты. Правда тут уже другой вопрос, обычно выпущенные сигналы моментально вызывают слот без добавления события в event. Может быть Qt::QueuedConnection и решил эту проблему, но все-таки. Хотелось бы до конца разобраться, поэтому я нашел пример от одного гуру В догонку о печальном: http://www.prog.org.ru/index.php?topic=7889 Немного о неблокируемых сокетах на базе QSocketDevice: http://doc.trolltech.com/qq/qq09-networkthread.html Это сообщение отредактировал(а) SABROG - 23.12.2008, 22:58 |
|||
|
||||
| null56 |
|
||||||||||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 721 Регистрация: 19.3.2008 Репутация: 6 Всего: 12 |
Обожаю людей, которые доконца стараются докопаться... я только что посмотрел код этого человека и понял почему у него разделились ветви...
И опять все потому что ты оказался прав.... еще раз повторю твои слова.... ну не буквально конечно "Если ты создаешь объект QThread в функции main, значит у тебя все слоты принадлежат основному eventloop", если в в функции run(), то уже дочернему.... Именно так он и сделал, но я - то нет... Давай посмотрим на его код, заметь, весь объект у него создается в run, включая ЕГО СЛОТЫ ЖЕ
тут же в конструкторе
и все это в run
Весь объект принадлежит вторичному или н-ному процессу... конечно здесь не нужен никакой moveTo У него взаимодействие происходит через вызов метода класса, который уже вызовет у объекта CxThread метод, который в свою очередь уже будет вызывать метод созданного в run объекта + чтобы вызвать метод в дочернем потоке, надо делать emit перед вызовом метода объета, я об этом не знал Единственное, что вот здесь, как показали опыты, делать не надо emit
и вот здесь
Нужно ли здесь делать???? по хорошему? Отлично, что разобрались... с этим вопросом |
||||||||||
|
|||||||||||
![]()
|
| Правила форума "С/С++: Кроссплатформенное программирование, QT/Gtk+/wxWidgets" | |
|
|
Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, JackYF, Любитель. |
| 0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей) | |
| 0 Пользователей: | |
| « Предыдущая тема | С/С++: Кроссплатформенное программирование, Qt/Gtk+/wxWidgets | Следующая тема » |
|
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |