Название: Проблема последовательности запуска слота при комуникации потоков Отправлено: yashaka от Апрель 07, 2010, 14:03 Итак, такая вот загогулина:
Вспомогательный поток (CalibrateThread): Код: void CalibrateThread::setCommand(const QString commandStr, const int pause) ... Код: void CalibrateThread::run() Главний поток (MainWindow): Код: calibrator = new CalibrateThread; Так вот, при работе программы происходит следующее: Вариант 1 - если поток calibrator запускается с приоритетом выше чем главный Все работает как "хочется", то есть: Калибратор посылает главному потоку сигнал readyToGetCommand, что готов принять команду и запускает еxec(), то есть ждет сигнала от главного с командой. Далее главный получает сигнал от калибратора и отвечает ему сигналом с командой, который приводит к запуску слота калибратора setCommand(...) в котором и запускается exit(0), что и приводит к выходу из exec() в калибраторе. Вариант 2 - если поток calibrator запускается с приоритетом меньше чем главный Програма зависает... Она не может выйти с exec() в калибраторе, так как всю свою работу (получение сигнала и отправка ответного с вызовом слота setCommand()) главный успел сделать еще до exec() в калибраторе. Итак вопрос: почему так происходит? Ведь при конекшене сигнала commandToSet() cо слотом setCommand() используется AutoConnection что в даном случае равно QueuedConnection, а это ведь должно значить, что слот выполнится не сразу, а когда ивент луп ему даст это сделать, то есть тогда когда запустится exec()... А выходит что слот запускается еще до этого... Это видно по крайней мере из того что пишется в логе, то есть что то типа такого: run(): forever {...}: at emit readyToGetCommand(); runNexTest(): at emit commandToSet(command, pause); setCommand(): at exit(0); setCommand(): after exit(0); run(): forever {...}: at exec(); КОНЕЦ:) то есть тут программа и начинает висеть. Вообще то есть еще и второй прикол, а именно в том, что когда при ВАРИАНТЕ 1 все работает то лог выглядит так: run(): forever {...}: at emit readyToGetCommand(); runNexTest(): at emit commandToSet(command, pause); setCommand(): at exit(0); setCommand(): after exit(0); run(): forever {...}: at exec(); run(): forever {...}: after exec(); тоесть программа не виснит, выходит из екзека, !но почему то лог не выглядит хотя бы вот так: run(): forever {...}: at emit readyToGetCommand(); runNexTest(): at emit commandToSet(command, pause); run(): forever {...}: at exec(); setCommand(): at exit(0); setCommand(): after exit(0); run(): forever {...}: after exec(); Но второй вопрос это такое... Просто может эта проблема завязана на том как у меня реализована запись в лог, и в какой последовательности будут обрабатываться мои ивенты записи в лог... Сейчас главное, на что я хочу получить ответ - это почему "не работает" queuedconnection, и если действительно это не моя ошибка, а это так и должно быть, то как тогда мне реализовать такую комуникацию чтобы все работало... Название: Re: Проблема последовательности запуска слота при комуникации потоков Отправлено: SABROG от Апрель 16, 2010, 16:14 Итак вопрос: почему так происходит? Ведь при конекшене сигнала commandToSet() cо слотом setCommand() используется AutoConnection что в даном случае равно QueuedConnection, а это ведь должно значить, что слот выполнится не сразу, а когда ивент луп ему даст это сделать, то есть тогда когда запустится exec()... А выходит что слот запускается еще до этого... QueuedConnection только если 2 объекта в разных потоках. exec() запускает локальный цикл событий в потоке, но существует еще и основной цикл событий в GUI'шном потоке, поэтому все сигналы, которые отсылаются из порожденного потока, где не запущен exec() спокойно доходят до объекта существующего в главном потоке.Название: Re: Проблема последовательности запуска слота при комуникации потоков Отправлено: Igors от Апрель 16, 2010, 22:11 Проверьте что CalibrateThread::setCommand выполняется где надо, а не в главной нитке. Это легко сделать распечатав QThread::currentThread() в 2-х местах
Название: Re: Проблема последовательности запуска слота при комуникации потоков Отправлено: yashaka от Апрель 19, 2010, 09:34 Проверил!
Действительно, CalibrateThread::setCommand выполняется в главном потоке... Спасибо за "просветление":) Теперь конечно все стало ясно... Переписал код, теперь использую вейткондишены, все работает... Но сейчас для меня полная загадка, в каких же тогда случаях может возникнуть ситуация с именно QueuedConnection и при каких условиях (при каких я понял - когда объекты в разных потоках, имею ввиду примеры...) его можно использовать... Название: Re: Проблема последовательности запуска слота при комуникации потоков Отправлено: Igors от Апрель 19, 2010, 11:40 Но сейчас для меня полная загадка, в каких же тогда случаях может возникнуть ситуация с именно QueuedConnection и при каких условиях (при каких я понял - когда объекты в разных потоках, имею ввиду примеры...) его можно использовать... В исходниках пишутКод: // check connection type На мой взгляд Вы перемудрили :) Все получается гораздо проще если строить управление "от сервера". Создали CalibratorThread и запустили в ней exec (один раз на всю ее жизнь). Это просто run по умолчанию. От сервера посылаете сигнал (команду), CalibratorThread ее отрабатывает и посылает сигнал "готово", сервер подает след. команду и.т.д. Когда нитка больше не нужна - сервер сделал ей quit - и все дела. Название: Re: Проблема последовательности запуска слота при комуникации потоков Отправлено: yashaka от Апрель 19, 2010, 14:12 Цитировать CalibratorThread был создан в главной нитке, значит currentThread == objectThread при вызове setCommand имеем DirectConnection. А вот при вызове readyToGetCommand уже currentThread != objectThread, значит QueuedConnection :) Наконец то до меня дошло полностью. Цитировать На мой взгляд Вы перемудрили Все получается гораздо проще если строить управление "от сервера". Создали CalibratorThread и запустили в ней exec (один раз на всю ее жизнь). Это просто run по умолчанию. От сервера посылаете сигнал (команду), CalibratorThread ее отрабатывает и посылает сигнал "готово", сервер подает след. команду и.т.д. Когда нитка больше не нужна - сервер сделал ей quit - и все дела. Очень даже может быть, что перемудрил:) По крайней мере, ваше предложение - намного элегантнее. Пока оставлю свою реализацию - как есть, но на следующий раз обязательно сначала попробую следовать вашему предложению. Большое спасибо за напутствия! |