Название: Блокируется интерфейс, не понятно почему Отправлено: Гурман от Август 16, 2011, 18:48 Есть plugin1, у которого есть GUI. Есть plugin2, у которого тоже есть GUI, и вызывается функция библиотеки, написанной на C, которая что-то считает. Из интерфейса plugin1 пользователь дает команду (кнопочкой) на запуск вычислений в plugin2, для чего тот вызывает функцию из библиотеки. Иногда библиотека плюется сообщениями, которые надо поймать и показать в GUI plugin1. Сообщения она выдает через функцию-хук, который присутствует в plugin2. Этот хук эмитирует сигнал, содержащий сообщение. Сигнал попадает в слот plugin1 и тот показывает текст. Все сигналы типа Qt::AutoConnection. Библиотека считает долго и нудно, разумеется, если все сделать влоб в одном потоке, то весь GUI будет блокирован. Поэтому библиотека помещена в отдельный QThread, откуда и вызывается. Так было сделано сразу, давно, и тогда в plugin2 использовался класс, наследовавший QMainWindow, в нем и был реализован сигнал с сообщением. Там все работает, как надо, ничего не блокируется. Но возникла необходимость сделать по-другому, и QMainWindow в новой версии plugin2 уже не наследуется. Поток создается, запускается, сообщения идут - но весь GUI (и plugin1, и plugin2, и остальных плагинов главного потока) оказывается блокирован. Предположил, что QMainWindow создает автоматически цикл обработки сообщений, благодаря чему с ним GUI работает. Попытался сделать тоже самое для plugin2, причем чтобы запустить в правильном порядке библиотеку и цикл сообщений, не придумал ничего лучше, как запустить счет по сигналу таймера после запуска цикла. То есть, вот так примерно (код не полный, явно незначимое выброшено, и plugin1 для простоты опущен, с ним нет проблем, поскольку со старым вариантом plugin2 отлично работает):
Код: class RunThread : public QThread в отладчике, как и ожидалось, появляется сначала starting loop, потом практически сразу starting processor. Библиотека считает, сообщения от нее идут, появляются в GUI plugin1. Однако весь GUI всё равно заблокирован... И вот тут я пока не вижу вариантов, куда копать. ??? Название: Re: Блокируется интерфейс, не понятно почему Отправлено: LisandreL от Август 16, 2011, 19:42 Для начала проверьте в каком потоке у вас реально идёт обсчёт ( qDebug() << QThread::currentThread(); из функции обсчёта и из гуя ) .
Название: Re: Блокируется интерфейс, не понятно почему Отправлено: Гурман от Август 16, 2011, 19:56 о, это хорошая идея... проверил
в считалке: Код: void RunThread::execute() и в запускалке Код: void plugin2::run_c_library() результат неожиданный - если в конструкторе RunThread нет вызова moveToThread(this) то нити одинаковые а если есть, то RunThread работает в своем потоке, но... интерфейс всё равно блокирован кстати, Qt:AutoConnection динамически в какой момент определяет как передается сигнал? в момент connect, или в момент передачи самого сигнала? мне что-то помнилось, что вроде в момент передачи... Название: Re: Блокируется интерфейс, не понятно почему Отправлено: Гурман от Август 16, 2011, 20:55 кажется, нащупал, в чем проблема... но пока еще не 100% уверен
Название: Re: Блокируется интерфейс, не понятно почему Отправлено: LisandreL от Август 16, 2011, 20:59 Вроде бы в момент вызова поток, в котором вызывается emit сравнивается с потоком принимающего потока: http://habrahabr.ru/blogs/qt_software/115835/
Попробуйте явно во всех коннектах прописать Qt::QueuedConnection, хотя бы для проверки. Название: Re: Блокируется интерфейс, не понятно почему Отправлено: Гурман от Август 16, 2011, 21:11 если сравнивается в момент вызова, значит это именно подстройка под разные потоки, то есть, соединения на потоки не влияют
на самом деле, пробовал, прописывал QueuedConnection у тех сигналов, которые эмитятся из потока, не помогает, да и не должно - в том варианте, который работает, соединения AutoConnection тут не совсем понятное поведение обнаружил - GUI таки откликается, но очень плохо, можно если долго и часто кликать, то один раз переключить окно, первая мысль, разумеется, что застревают события, но вставка processEvents в функцию вывода текста не помогла, хотя должна была бы, если дело в этом, и опять же - в работающем варианте вызова processEvents нет Название: Re: Блокируется интерфейс, не понятно почему Отправлено: LisandreL от Август 16, 2011, 21:39 тут не совсем понятное поведение обнаружил - GUI таки откликается, но очень плохо Такое наблюдал, когда в главном потоке очень часто вызывался слот из очереди, изменяющий содержимое окна. Может у вас тоже в новом алгоритме emit'ы из обработчика слишком частые?Название: Re: Блокируется интерфейс, не понятно почему Отправлено: Гурман от Август 16, 2011, 21:48 Проблема явно прохождении событий интерфейса - они набиваются в очередь, и если, например, повозить окно, то пока счет идет, оно не возится, но когда счет заканчивается, оно прыгает по траектории.
Цитировать Может у вас тоже в новом алгоритме emit'ы из обработчика слишком частые? Алгоритм счета тот же, что и в старом варианте, С-библиотека просто та же самая. И эмиты точно такие же, ровно с той же частотой. Но там все без проблем работает, а тут нет. Причем, блокируется не одно окно, плагины приложения создают свои окна - события перестают проходить ко всем окнам. И опять же - processEvents не помогает ни в какую. Специально протащил указатель на главное QApplication до вывода строк, вставил его прямо перед emit: Код: void plugin2::lib_message( QString msg ) не помогает. На самом деле, трансляция сигналов внутри там сама делает processEvents, поскольку сигналы попадают в event loop. То есть, и не удивительно, что не помогает. Удивительно, что сигналы не проходят. Сейчас попробую еще один тест... О! Действительно, проблема похоже в частой передаче сигналов. Отключил выдачу сообщений из библиотеки - все стало работать. Теперь еще более не понятно, поскольку в старой версии все работает без этого. Название: Re: Блокируется интерфейс, не понятно почему Отправлено: LisandreL от Август 16, 2011, 22:19 В слоте изменяете GUI? Вот у вас вся очередь событий и забита вызовом вашего слота и перерисовкой.
В слоте аккумулируйте изменения в каком-нибудь массиве/списке и с некоторой периодичностью вызывайте слот, который все эти изменения будет применять скопом. Я писал примерно так: Слот, соединённый с обработчиком: Код
Вывод в гуй: Код: void Widget :: updateLog() Название: Re: Блокируется интерфейс, не понятно почему Отправлено: Гурман от Август 16, 2011, 22:41 в слоте сообщения валится в QPlainTextEdit, типа консоль
но, черт побери, в СТАРОЙ ВЕРСИИ ТОЖЕ САМОЕ, и все без проблем работает... причем там даже QTextEdit, а не QPlainTextEdit, он вроде еще медленнее а, не, вру - в обоих случаях QTextEdit, видимо у QPlainTextEdit чего-то не хватало, не помню уже точно ну старая версия немного медленнее выводит, но всего лишь в 2 раза чудеса какие-то... Название: Re: Блокируется интерфейс, не понятно почему Отправлено: Гурман от Август 17, 2011, 00:14 Все, победил. Немного подумав, сделал это соединение для выдачи сообщений типа Qt::BlockingQueuedConnection. И все стало, как надо. Никакие дополнительные буфера не нужны, поскольку очередь - это и так буфер, а при этом типе поток приостанавливается, пока сигнал не будет передан.
После чего... полез в старый код, и обнаружил там такой же тип соединения у старого плагина. ;D ;D ;D То есть, я это все делал 2 года назад, и... забыл. Ну ничего, пусть здесь остается обсуждение, может кому-то еще пригодится. BTW: когда я обнаружил, что дело в передаче сигналов, то переделал класс RunThread на вот такой: Код: class RunThread : public QThread и все прекрасно работает, без всяких таймеров и exec() |