Название: Зависание GUI Отправлено: Vladimir от Март 20, 2012, 11:35 Доброго дня! Есть такая проблемка: по сети, в отдельном потоке приходят данные, заполняя глобальную структуры данных, объявленную как extern! После того как вся инфа была получена отсылается сигнал, связанный со слотом в главном потоке, который отрисовывает полученную инфу из глобальной структуры! При этом сигналы невсегда доходят и интерфейс программы висит! Может нужно заменить сигналы на события? Если да, то как это сделать.. нужно реализовывать собственный класс событий??
Название: Re: Зависание GUI Отправлено: Пантер от Март 20, 2012, 11:36 Код показывай.
Название: Re: Зависание GUI Отправлено: Vladimir от Март 20, 2012, 11:56 код достаточно большой.. основные выдержки:
прием данных Код: void TSignalReceiver::run( ) конект сигнала со слотом Код: connect(tSignReceiv,SIGNAL(onRecvSignal()),indWin,SLOT(slotDrawIndicat())); // отрисовка Код: void COpenGlEngine::slotDrawIndicat() Название: Re: Зависание GUI Отправлено: V1KT0P от Март 20, 2012, 11:59 Так и не понял проблема в том что только сигнал не доходит или GUI зависает. Или и то и другое? А как ты в отдельный поток код обработки выносишь?
Название: Re: Зависание GUI Отправлено: Пантер от Март 20, 2012, 12:02 Что-то у тебя напутано. Отправляй структуру в сигнале и лови ее в слоте, а не используй глобальную структуру.
Название: Re: Зависание GUI Отправлено: mutineer от Март 20, 2012, 12:03 и больше кода не помешает
Название: Re: Зависание GUI Отправлено: Vladimir от Март 20, 2012, 12:09 Так и не понял проблема в том что только сигнал не доходит или GUI зависает. Или и то и другое? А как ты в отдельный поток код обработки выносишь? и сигнал не доходит, и все элементы интерфейса не реагируют на нажатие, всё дико висит! "А как ты в отдельный поток код обработки выносишь?" в каком плане? из главного потока запускается поток TSignalReceiver и там принимаются данные..! с этим проблем нет, а вот в том что они не всегда читаются.. ибо сигнал не всегда доходит - проблема! Название: Re: Зависание GUI Отправлено: Vladimir от Март 20, 2012, 12:12 а каким образом передать структуры в сигнале и принять ее в слоте?
структура Код: struct dataPacket дойдет ли она корректно и всегда, как только получены данные, если даже просто сигнал не всегда доходит? Название: Re: Зависание GUI Отправлено: V1KT0P от Март 20, 2012, 12:22 Так и не понял проблема в том что только сигнал не доходит или GUI зависает. Или и то и другое? А как ты в отдельный поток код обработки выносишь? и сигнал не доходит, и все элементы интерфейса не реагируют на нажатие, всё дико висит! "А как ты в отдельный поток код обработки выносишь?" в каком плане? из главного потока запускается поток TSignalReceiver и там принимаются данные..! с этим проблем нет, а вот в том что они не всегда читаются.. ибо сигнал не всегда доходит - проблема! Название: Re: Зависание GUI Отправлено: mutineer от Март 20, 2012, 12:23 Если да то ты его после объявления moveToThread-ил сам в себя? Вот не надо так делать Название: Re: Зависание GUI Отправлено: V1KT0P от Март 20, 2012, 12:29 Если да то ты его после объявления moveToThread-ил сам в себя? Вот не надо так делать Название: Re: Зависание GUI Отправлено: Vladimir от Март 20, 2012, 12:33 Что значит "moveToThread-ил сам в себя"??
а наследуется так Код: class TSignalReceiver : public TAbstractThread Название: Re: Зависание GUI Отправлено: mutineer от Март 20, 2012, 12:34 Покажи хедеры обоих классов (прием данных и гуй), как они создаются и как связываются
Название: Re: Зависание GUI Отправлено: Vladimir от Март 20, 2012, 12:48 class TSignalReceiver описание
Код: class TSignalReceiver : public TAbstractThread Код: TSignalReceiver::TSignalReceiver(const QString& name, QObject* p ) : class TAbstractThread описание Код: class TAbstractThread : public QThread В главной форме окна создается tSignReceiv = new TSignalReceiver( "RcvSig", this ); там же и связывается connect(tSignReceiv,SIGNAL(onRecvSignal()),indWin,SLOT(slotDrawIndicat())); Проект достаточно большой поэтому сложно выложить весь код подробно, будет много! Да, кстати, программа под Linux на Qt 4.8! Название: Re: Зависание GUI Отправлено: Vladimir от Март 20, 2012, 12:55 Закомментировал отрисовку и картина вообще удивлять стала! Чередование сообщений получается очень разное:
QDebug() << " в потоке сразу после приема данных"; QDebug() << " в слоте отрисовки"; Хотелось бы видеть: QDebug() << " в потоке сразу после приема данных"; QDebug() << " в слоте отрисовки"; QDebug() << " в потоке сразу после приема данных"; QDebug() << " в слоте отрисовки"; QDebug() << " в потоке сразу после приема данных"; QDebug() << " в слоте отрисовки"; А получается: QDebug() << " в потоке сразу после приема данных"; QDebug() << " в слоте отрисовки"; QDebug() << " в слоте отрисовки"; QDebug() << " в слоте отрисовки"; QDebug() << " в слоте отрисовки"; QDebug() << " в потоке сразу после приема данных"; QDebug() << " в потоке сразу после приема данных"; QDebug() << " в слоте отрисовки"; В общем различные комбинации, но не последовательно одна за другой.. Название: Re: Зависание GUI Отправлено: mutineer от Март 20, 2012, 13:00 Последовательно вряд ли получится - это ж разные потоки и общение между ними идет через eventLoop
Название: Re: Зависание GUI Отправлено: Vladimir от Март 20, 2012, 13:02 Если реализовать заполнение структуры в том же потоке, но не данными по сети, то работает все как надо! проблемы начинаются, когда инфа начинает приходить по сети.. может как-то нужно синхронизировать этот процесс??
Название: Re: Зависание GUI Отправлено: Bepec от Март 20, 2012, 13:31 Мб минимально компилируемый пример?
Название: Re: Зависание GUI Отправлено: mutineer от Март 20, 2012, 13:35 Последовательно вряд ли получится - это ж разные потоки и общение между ними идет через eventLoop Пардон, скорее всего должен быть прямой вызов, а не через eventLoop Название: Re: Зависание GUI Отправлено: V1KT0P от Март 20, 2012, 13:43 Последовательно вряд ли получится - это ж разные потоки и общение между ними идет через eventLoop Пардон, скорее всего должен быть прямой вызов, а не через eventLoop Название: Re: Зависание GUI Отправлено: LisandreL от Март 20, 2012, 13:46 А получается: Возможно отрисовывать не успеваете с той скоростью, с которой получаете данные (да ещё за счёт глобальной переменной и перетираете одни другими).QDebug() << " в потоке сразу после приема данных"; QDebug() << " в слоте отрисовки"; QDebug() << " в слоте отрисовки"; QDebug() << " в слоте отрисовки"; QDebug() << " в слоте отрисовки"; QDebug() << " в потоке сразу после приема данных"; QDebug() << " в потоке сразу после приема данных"; QDebug() << " в слоте отрисовки"; В общем различные комбинации, но не последовательно одна за другой.. Вот так же всё по очереди будет: connect(tSignReceiv,SIGNAL(onRecvSignal()),indWin,SLOT(slotDrawIndicat()), Qt::BlockingQueuedConnection ); Название: Re: Зависание GUI Отправлено: mutineer от Март 20, 2012, 13:53 Последовательно вряд ли получится - это ж разные потоки и общение между ними идет через eventLoop Пардон, скорее всего должен быть прямой вызов, а не через eventLoop Ну вот если рассужадть логически. Принимающий объект живет в GUI-треде. Отправляющий объект кто? Наследник QThread. По идее он тоже живет в GUI-треде. Значит Qt должен использовать прямой вызов Название: Re: Зависание GUI Отправлено: V1KT0P от Март 20, 2012, 13:57 Ну вот если рассужадть логически. Принимающий объект живет в GUI-треде. Отправляющий объект кто? Наследник QThread. По идее он тоже живет в GUI-треде. Значит Qt должен использовать прямой вызов Ну так если обработчик слотов треда в главном треде то все что в нем будет выполняться будет тормозить GUI. А он хочет вынести его в отдельный.Название: Re: Зависание GUI Отправлено: arttr от Март 20, 2012, 14:18 Да, да, да, вот в точности такая ситуация была QTcpSocket крутится в отдельном потоке, принимает данные, в этом же потоке происходит их (довольно сложное) преобразование, а потом они эмитятся в ГУИ-поток...головняка на неделю было...
проблему решили так: отказались от переопределения метода run в классе треда. Написали свой класс Thread, в котором был указатель на QThread как приватное поле QThread* thread. Написали слот Код: void Thread::start() Код: this->deleteLater(); Еще про "сеть в отдельном потоке". Cетевые сокеты (QTcpSocket точно) являются асинхронными девайсами, это значит им для нормальной работы нужен работающий цикл обработки событий, а это в свою очередь значит, что создавать/удалять, создавать подключение/разрывать подключение, считывать/записывать нужно в работающем потоке. Поэтому и пришлось делать метод threadStarted. Теперь структуру Вашу, объявленную extern'ом, если я правильно понял, то она же живет в главном потоке, а заполняется в дочернем данными по сети, еще бы ГУЙ не повис...делайте структуру в своем дочернем потоке и эмитируйте куда хотите...никакие blockingConnection не нужны будут Дополнение: всем полям класса Thread обязательно делать moveToThread(thread) Название: Re: Зависание GUI Отправлено: Vladimir от Март 20, 2012, 15:05 Вроде выше писали, что moveToThread не есть хорошее решение.. что-то я по ходу жестко тупанул) зачем мне вообще отсылать сигнал, что данные пришли.. в глобальную структуры я эти данные записываю, а когда нужно отрисовать просто считываю! без всякого сигнала.. вроде так и работает! рисуется по данным из сети, но интерфейс всеравно притормаживает.. не так жестко конечно, но есть еще..
Название: Re: Зависание GUI Отправлено: Bepec от Март 20, 2012, 15:24 Код в студию! Тогда и тормоза уберём. Причёску сделаем, автомат выдадим и на окопы ЗА РОДИНУУУ!!!!
Название: Re: Зависание GUI Отправлено: arttr от Март 20, 2012, 15:49 Цитировать Вроде выше писали, что moveToThread не есть хорошее решение.. moveToThread - это хорошее решение, если понимать зачем оно нужно.Цитировать интерфейс всеравно притормаживает.. не так жестко конечно, но есть еще.. интерфейс и будут замораживаться, именно для этого весь ресурсоемкий код выносят в отдельный поток. Получение данных по сети всяко происходит медленнее, чем отрисовка ГУИ => ГУИ притормаживаетНазвание: Re: Зависание GUI Отправлено: mutineer от Март 20, 2012, 15:50 Вроде выше писали, что moveToThread не есть хорошее решение.. moveToThread хорошее решение, moveToThread(this) нехорошее Название: Re: Зависание GUI Отправлено: Bepec от Март 20, 2012, 15:56 Чем? :)
mutineer - Если ты точно незнаешь, то не советуй :) А спор у нас таки пришёл к тому, что это РАВНОПРАВНОЕ решение ;) Название: Re: Зависание GUI Отправлено: mutineer от Март 20, 2012, 15:59 Чем? :) mutineer - Если ты точно незнаешь, то не советуй :) А спор у нас таки пришёл к тому, что это РАВНОПРАВНОЕ решение ;) Ваш спор пришел к тому, что "я 50 раз запускал, у меня ниче не крешится, так что способ хороший", а с потоками так нельзя. Так что ты тоже точно не знаешь что это нормальное решение Название: Re: Зависание GUI Отправлено: Vladimir от Март 20, 2012, 16:23 получается данные приходят по сети, каждые 12 мс и это реализовано в отдельном потоке.. а отрисовка происходит по таймеру, каждые 40 мс (вызывается updateGL()) в GUI потоке! Данные накапливаются в глобальной структуре и каждые 40 мс отрисовываются на экране средствами OpenGL! при этом при открытии диалоговых окон, нажатии на кнопки программа чуток подвисает и в этот момент данные могут не отрисоваться (в случае открытия диалоговых окон)..
Название: Re: Зависание GUI Отправлено: Bepec от Март 20, 2012, 16:49 Помоему у вас что-то с архитектурой. Т.е. к примеру у вас каждые 15 мс полная отрисовка + приём данных в основном потоке.
Название: Re: Зависание GUI Отправлено: Vladimir от Март 20, 2012, 17:33 может быть и с архитектурой.. ибо прога переделывается не из лучшего варианта! но сейчас реализовано так, что данные принимаются в отдельном потоке (не в главном), а отрисовываются в главном через глобальную структуру! если не использовать эту глобальную структуру, то как передать данные из дочернего потока в главный?
Название: Re: Зависание GUI Отправлено: V1KT0P от Март 20, 2012, 17:37 может быть и с архитектурой.. ибо прога переделывается не из лучшего варианта! но сейчас реализовано так, что данные принимаются в отдельном потоке (не в главном), а отрисовываются в главном через глобальную структуру! если не использовать эту глобальную структуру, то как передать данные из дочернего потока в главный? Пошли сигнал с указателем на структуру.Название: Re: Зависание GUI Отправлено: Vladimir от Март 20, 2012, 17:45 так это будет правельнее, чем использование глобальной структуры? тобишь накапливать данные сколько мне нужно, а как понадобиться отрисовать отослать сигнал с указателем на структуру и перерисовать?
Название: Re: Зависание GUI Отправлено: V1KT0P от Март 20, 2012, 17:50 так это будет правельнее, чем использование глобальной структуры? тобишь накапливать данные сколько мне нужно, а как понадобиться отрисовать отослать сигнал с указателем на структуру и перерисовать? Да.Название: Re: Зависание GUI Отправлено: arttr от Март 20, 2012, 18:11 Vladimir, возможно я не правильно объясняю, возможно Вы меня просто не хотите понять.
Давайте попробуем еще раз на пальцах(с потоками в Qt не так просто, как кажется на первый взгляд): разберем, что происходит. В ГУИ-потоке живет некая глобальная структура; в ГУИ-потоке живут все виджеты и вся графика, их отрисовка происходит в цикле событий ГУИ-шного потока. Также, у Вас есть дочерний поток, который держит некое сетевое соединение. У этот дочерний поток крутит свой цикл обработки событий и именно в нем работает сокет сетевое соединение. Из дочернего потоке Вы ломитесь в главный поток, чтобы записать данные в структуру. и на этом цикл обработки событий гуи-потока притормаживается(читайте "притормаживается графика"), т.к. главный поток в это время посто ждет. Внимательно прочитайте http://habrahabr.ru/post/115830/ (http://habrahabr.ru/post/115830/), особенно пункты "События и цикл обработки событий" и "Блокирование цикла обработки событий". Человек все подробно и просто расписал. Насчет как передавать эту структуру для отрисовки, V1KT0P предложил: Цитировать Пошли сигнал с указателем на структуру. тоже самое предлагал я раньше: Цитировать делайте структуру в своем дочернем потоке и эмитируйте куда хотите добавлю только что лучше передавать константную ссылку или просто копию.Название: Re: Зависание GUI Отправлено: Vladimir от Март 20, 2012, 18:28 Обязательно почитаю! Спасибо за помощь, буду пробовать..
|