Russian Qt Forum
Ноябрь 26, 2024, 02:05 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: Еще раз "UI только в главном потоке"  (Прочитано 5719 раз)
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« : Январь 20, 2011, 12:57 »

Добрый день

Стандартная ситуация - в ходе выполнения параллельных вычислений необходимо обновлять индикатор. Организовывать посылку сигналов или др. взаимодействие между нитками - в данном случае неприемлемо медленно. Сделал так
Код
C++ (Qt)
#pragma omp master  
UpdateIndicator();          // выполняется только главной ниткой
 
Это работает, но вылезает др. проблема: нитки в разное время заканчивают вычисления. Поэтому нередко получается что главная нитка уже отстрелялась а остальные еще пашут - индикатор "замораживается" в конце вычислений.

Есть др. возможность
Код
C++ (Qt)
#pragma omp single nowait  
UpdateIndicator();          // выполняется только одной (любой) ниткой
 
Но тут непонятки с "UI только в главном потоке" - что же имеется ввиду.
Вопросы:

1) Могу ли я в Qt вызвать рисование из др нитки? Что QWidget UI должны быть созданы только в главной нитке, что нельзя вызывать рисование 2-мя или более нитками - это ясно. Но могу ли я просто "перерисоваться" из любой нитки?

2) Могу ли я делать это ("1") в нативном UI (не Qt)?

Спасибо
Записан
Fat-Zer
Гость
« Ответ #1 : Январь 20, 2011, 15:54 »

1) вообще говоря нет... правда в линуксе у меня это прокатывало нормально, но при переносе на винду всё рухнуло.
2)"нативный" это винапи/апи иксов подразумевается?

А чем сигнал не устраивает? шлите его только если процент выполнения изменился... при посылке 100 раз из потока длительностью пару секунд на скорости не должен сказаться...

ЗЫ: я же правильно понимаю:морда на Qt полностью, а поток через QThread реализован?
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #2 : Январь 22, 2011, 11:10 »

ЗЫ: я же правильно понимаю:морда на Qt полностью, а поток через QThread реализован?
Нет, UI нативное а нитки через OpenMP  Улыбающийся

В общем проверил я с нативным(и) OC и завалить мне не удалось. Также не вылетают нативные вызовы событий (WaitNextEvent и GetMessage). Однако одну проблему я уже получил - не бычит семафор в 64 бит. И кто знает сколько их еще будет. В описаниях нигде не сказано явно что, мол, "только из главной нитки". Но если копнуть напр. популярное GetMessage (Вындоуз) то всплывают детали (типа "просто message" и "thread message"). Разбираться во всем этом невыгодно/непрактично. Поэтому придется пустить все вычисления через еще 1 нитку (и там уже их параллелить), а главную нитку оставить для UI.
Записан
Akon
Гость
« Ответ #3 : Январь 22, 2011, 14:16 »

... Это работает, но вылезает др. проблема: нитки в разное время заканчивают вычисления. Поэтому нередко получается что главная нитка уже отстрелялась а остальные еще пашут - индикатор "замораживается" в конце вычислений.

ИМХО, обновлять гуй из других потоков, кроме главного, плохое (неоправдано сложное) дизайнерское решение. Из гуй-потока убери вычисления, тогда он станет пошустрей (быстрая обработка очереди сообщений). Рабочие потоки скидывают информацию о прогрессе гуй-потоку асинхронно (сигнал с QueuedConnection).

Пример (из практики): идет запись звука (системный рабочий поток из которого нельзя вызывать гуи функции), необходимо отображать на экране в реальном времени амплитудный спектр сигнала (из главного потока). 
Решение: расчет спектра производится в рабочем потоке, результат упаковывается и асинхронно пересылается в главный поток. При этом запросто может быть ситуация, когда в очереди сообщений главного потока находится > 1 команды на обновление гуя. В целях оптимизации (когда допустимо обработать только последнюю команду на обновление) вводится атомарный счетчик, показывающий количество команд в очереди, т.о. главный поток, извлекая все команды, реально обрабатывал всегда последнюю.

Надеюсь, чем-то был полезен.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #4 : Январь 22, 2011, 15:11 »

ИМХО, обновлять гуй из других потоков, кроме главного, плохое (неоправдано сложное) дизайнерское решение. Из гуй-потока убери вычисления, тогда он станет пошустрей (быстрая обработка очереди сообщений). Рабочие потоки скидывают информацию о прогрессе гуй-потоку асинхронно (сигнал с QueuedConnection).
Это все понятно и сам так много раз делал. Просто в данном случае индикатор и есть "все UI", поэтому со стандартным подходом кое-что получается сложнее. Пример:

- пользователь нажал "pause". В примитивном варианте
Код
C++ (Qt)
#pragma omp master  
UpdateIndicator();  
 
Это работает как надо, причем без всяких усилий. UpdateIndicator вызвал event loop и там висит (пока пользователь не снимет паузу). Остальные нитки закончат свою текущую задачу и будут ждать на барьере. А вот сделать это же через посылку в главную нитку - совсем непросто учитывая что параллельных участков десятки.


Записан
Akon
Гость
« Ответ #5 : Январь 22, 2011, 17:04 »

Код:
#pragma omp master   
UpdateIndicator(); 

Насколько я понимаю (к сожалению не использовал OpenMP), это синхронный вызов. Т.е. рабочий поток, дойдя то точки UpdateIndicator()  остановится и будет ждать исполнения UpdateIndicator() из контекста основного потока. Если это так, то это плохое решение, поскольку имеется блокировка рабочих потоков в зависимости от готовности главного потока.

Если, к примеру, 10 потоков, т.е. на каждый нагрузка 10%, в процессе работы асинхронно помещают в очередь главного потока свой текущий процент (достаточно int типа); главный поток все суммирует и отображает. Если пользователь приостанавливает процесс обработки (пауза), потоки приостанавливаются, главный поток ждет приостановки всех потоков, обрабатывает все сигналы из очереди (QCoreApplication::processEvents(), а лучше только асинхронные вызовы - фильтр QEvent::Metacall) и отображает реально текущее значение прогресса. В чем проблема?   
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #6 : Январь 22, 2011, 17:43 »

Код:
#pragma omp master   
UpdateIndicator(); 
Насколько я понимаю (к сожалению не использовал OpenMP), это синхронный вызов. Т.е. рабочий поток, дойдя то точки UpdateIndicator()  остановится и будет ждать исполнения UpdateIndicator() из контекста основного потока. Если это так, то это плохое решение, поскольку имеется блокировка рабочих потоков в зависимости от готовности главного потока.
В OpenMP "master" - эта нитка из которой стартовал параллельный регион, она может быть или не быть главной ниткой application. Master-нитка участвует в вычислениях так же как и "рабочие". Директива omp master не создает барьера, просто master займется индикатором, а потом продолжит считать. А остальные рабочие нитки просто "обходят" UpdateIndicator и считают дальше. Словом, никто никого не ждет.

Если, к примеру, 10 потоков, т.е. на каждый нагрузка 10%, в процессе работы асинхронно помещают в очередь главного потока свой текущий процент (достаточно int типа); главный поток все суммирует и отображает. Если пользователь приостанавливает процесс обработки (пауза), потоки приостанавливаются, главный поток ждет приостановки всех потоков, обрабатывает все сигналы из очереди (QCoreApplication::processEvents(), а лучше только асинхронные вызовы - фильтр QEvent::Metacall) и отображает реально текущее значение прогресса. В чем проблема?   
А кто и как приостановит выполнение ниток? Ну главная нитка получила паузу, и что она будет делать? Взвести глобальный флажок "пауза" который понимается всеми считающими? Так это хорошо для 1-2 параллельных участков. А когда их гораздо больше? Да и "остановить" не так просто как "отменить".
Код
C++ (Qt)
if (flagPause) {
// и что здесь?
}
 
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.169 секунд. Запросов: 23.