Название: Еще раз "UI только в главном потоке" Отправлено: Igors от Январь 20, 2011, 12:57 Добрый день
Стандартная ситуация - в ходе выполнения параллельных вычислений необходимо обновлять индикатор. Организовывать посылку сигналов или др. взаимодействие между нитками - в данном случае неприемлемо медленно. Сделал так Код Это работает, но вылезает др. проблема: нитки в разное время заканчивают вычисления. Поэтому нередко получается что главная нитка уже отстрелялась а остальные еще пашут - индикатор "замораживается" в конце вычислений. Есть др. возможность Код Но тут непонятки с "UI только в главном потоке" - что же имеется ввиду. Вопросы: 1) Могу ли я в Qt вызвать рисование из др нитки? Что QWidget UI должны быть созданы только в главной нитке, что нельзя вызывать рисование 2-мя или более нитками - это ясно. Но могу ли я просто "перерисоваться" из любой нитки? 2) Могу ли я делать это ("1") в нативном UI (не Qt)? Спасибо Название: Re: Еще раз "UI только в главном потоке" Отправлено: Fat-Zer от Январь 20, 2011, 15:54 1) вообще говоря нет... правда в линуксе у меня это прокатывало нормально, но при переносе на винду всё рухнуло.
2)"нативный" это винапи/апи иксов подразумевается? А чем сигнал не устраивает? шлите его только если процент выполнения изменился... при посылке 100 раз из потока длительностью пару секунд на скорости не должен сказаться... ЗЫ: я же правильно понимаю:морда на Qt полностью, а поток через QThread реализован? Название: Re: Еще раз "UI только в главном потоке" Отправлено: Igors от Январь 22, 2011, 11:10 ЗЫ: я же правильно понимаю:морда на Qt полностью, а поток через QThread реализован? Нет, UI нативное а нитки через OpenMP :)В общем проверил я с нативным(и) OC и завалить мне не удалось. Также не вылетают нативные вызовы событий (WaitNextEvent и GetMessage). Однако одну проблему я уже получил - не бычит семафор в 64 бит. И кто знает сколько их еще будет. В описаниях нигде не сказано явно что, мол, "только из главной нитки". Но если копнуть напр. популярное GetMessage (Вындоуз) то всплывают детали (типа "просто message" и "thread message"). Разбираться во всем этом невыгодно/непрактично. Поэтому придется пустить все вычисления через еще 1 нитку (и там уже их параллелить), а главную нитку оставить для UI. Название: Re: Еще раз "UI только в главном потоке" Отправлено: Akon от Январь 22, 2011, 14:16 ... Это работает, но вылезает др. проблема: нитки в разное время заканчивают вычисления. Поэтому нередко получается что главная нитка уже отстрелялась а остальные еще пашут - индикатор "замораживается" в конце вычислений. ИМХО, обновлять гуй из других потоков, кроме главного, плохое (неоправдано сложное) дизайнерское решение. Из гуй-потока убери вычисления, тогда он станет пошустрей (быстрая обработка очереди сообщений). Рабочие потоки скидывают информацию о прогрессе гуй-потоку асинхронно (сигнал с QueuedConnection). Пример (из практики): идет запись звука (системный рабочий поток из которого нельзя вызывать гуи функции), необходимо отображать на экране в реальном времени амплитудный спектр сигнала (из главного потока). Решение: расчет спектра производится в рабочем потоке, результат упаковывается и асинхронно пересылается в главный поток. При этом запросто может быть ситуация, когда в очереди сообщений главного потока находится > 1 команды на обновление гуя. В целях оптимизации (когда допустимо обработать только последнюю команду на обновление) вводится атомарный счетчик, показывающий количество команд в очереди, т.о. главный поток, извлекая все команды, реально обрабатывал всегда последнюю. Надеюсь, чем-то был полезен. Название: Re: Еще раз "UI только в главном потоке" Отправлено: Igors от Январь 22, 2011, 15:11 ИМХО, обновлять гуй из других потоков, кроме главного, плохое (неоправдано сложное) дизайнерское решение. Из гуй-потока убери вычисления, тогда он станет пошустрей (быстрая обработка очереди сообщений). Рабочие потоки скидывают информацию о прогрессе гуй-потоку асинхронно (сигнал с QueuedConnection). Это все понятно и сам так много раз делал. Просто в данном случае индикатор и есть "все UI", поэтому со стандартным подходом кое-что получается сложнее. Пример:- пользователь нажал "pause". В примитивном варианте Код Это работает как надо, причем без всяких усилий. UpdateIndicator вызвал event loop и там висит (пока пользователь не снимет паузу). Остальные нитки закончат свою текущую задачу и будут ждать на барьере. А вот сделать это же через посылку в главную нитку - совсем непросто учитывая что параллельных участков десятки. Название: Re: Еще раз "UI только в главном потоке" Отправлено: Akon от Январь 22, 2011, 17:04 Код: #pragma omp master Насколько я понимаю (к сожалению не использовал OpenMP), это синхронный вызов. Т.е. рабочий поток, дойдя то точки UpdateIndicator() остановится и будет ждать исполнения UpdateIndicator() из контекста основного потока. Если это так, то это плохое решение, поскольку имеется блокировка рабочих потоков в зависимости от готовности главного потока. Если, к примеру, 10 потоков, т.е. на каждый нагрузка 10%, в процессе работы асинхронно помещают в очередь главного потока свой текущий процент (достаточно int типа); главный поток все суммирует и отображает. Если пользователь приостанавливает процесс обработки (пауза), потоки приостанавливаются, главный поток ждет приостановки всех потоков, обрабатывает все сигналы из очереди (QCoreApplication::processEvents(), а лучше только асинхронные вызовы - фильтр QEvent::Metacall) и отображает реально текущее значение прогресса. В чем проблема? Название: Re: Еще раз "UI только в главном потоке" Отправлено: Igors от Январь 22, 2011, 17:43 Код: #pragma omp master Если, к примеру, 10 потоков, т.е. на каждый нагрузка 10%, в процессе работы асинхронно помещают в очередь главного потока свой текущий процент (достаточно int типа); главный поток все суммирует и отображает. Если пользователь приостанавливает процесс обработки (пауза), потоки приостанавливаются, главный поток ждет приостановки всех потоков, обрабатывает все сигналы из очереди (QCoreApplication::processEvents(), а лучше только асинхронные вызовы - фильтр QEvent::Metacall) и отображает реально текущее значение прогресса. В чем проблема? А кто и как приостановит выполнение ниток? Ну главная нитка получила паузу, и что она будет делать? Взвести глобальный флажок "пауза" который понимается всеми считающими? Так это хорошо для 1-2 параллельных участков. А когда их гораздо больше? Да и "остановить" не так просто как "отменить".Код
|