Переброска сообщений между потоками
От: kvser  
Дата: 15.01.10 06:33
Оценка:
Здравствуйте!

Есть поток 1, который создает поток 2 и показывает прогрессбар. 2 занимается каким-либо расчетом, а 1 — показывает прогрессбар этого расчета.
После каждой итерации 2 вызывает функцию обработчик, которая увеличивает процент выполнения у прогрессбара.
В результате получается, что продвижение прогрессбара происходит во втором потоке, а хотелось бы, чтобы второй поток вообще не касался прогрессбара.

Надо переслать сообщение из второго потока в первый так, чтобы вызов функции продвижения прогрессбара был из первого потока.
Какие есть варианты? Платформа не обязательно win.
Re: Переброска сообщений между потоками
От: jazzer Россия Skype: enerjazzer
Дата: 15.01.10 07:11
Оценка:
Здравствуйте, kvser, Вы писали:

K>Есть поток 1, который создает поток 2 и показывает прогрессбар. 2 занимается каким-либо расчетом, а 1 — показывает прогрессбар этого расчета.


Поток 2 пишет свой прогресс в какую-нть мелкую переменную и спокойно занимается своими делами, а поток 1 периодически, по своему расписанию, в эту переменную заглядывает, берет оттуда чиселку и рисует прогресс-бар. Всё.
Если очень хочется, можно сделать доступ атомарным или повесить спинлок, хотя я бы не заморачивался, оно того не стоит.
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[2]: Переброска сообщений между потоками
От: kvser  
Дата: 15.01.10 07:23
Оценка:
Здравствуйте, jazzer, Вы писали:
J>Поток 2 пишет свой прогресс в какую-нть мелкую переменную и спокойно занимается своими делами, а поток 1 периодически, по своему расписанию, в эту переменную заглядывает, берет оттуда чиселку и рисует прогресс-бар. Всё.

периодически = по таймеру? или еще есть варианты
А то получается, что 1 поток большую часть времени вхолостую будет опрашивать новое значение
Re[3]: Переброска сообщений между потоками
От: jazzer Россия Skype: enerjazzer
Дата: 15.01.10 07:27
Оценка: +1
Здравствуйте, kvser, Вы писали:

K>Здравствуйте, jazzer, Вы писали:

J>>Поток 2 пишет свой прогресс в какую-нть мелкую переменную и спокойно занимается своими делами, а поток 1 периодически, по своему расписанию, в эту переменную заглядывает, берет оттуда чиселку и рисует прогресс-бар. Всё.

K>периодически = по таймеру? или еще есть варианты

K>А то получается, что 1 поток большую часть времени вхолостую будет опрашивать новое значение
ну да, раз в секунду за глаза, а в чем проблема? он должен еще чем-то заниматься? Ну так он за секунду кучу всего успеет сделать.
Более того, можно родить третий поток, который будет заниматься исключительно прогресс-баром, если не хочешь делить функционал первого потока.
кстати, ты уверен, что хочешь апдейтить прогресс-бар на каждый чих второго потока? А если он отработает слишком быстро?
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re: Переброска сообщений между потоками
От: remark Россия http://www.1024cores.net/
Дата: 15.01.10 07:48
Оценка:
Здравствуйте, kvser, Вы писали:

K>Есть поток 1, который создает поток 2 и показывает прогрессбар. 2 занимается каким-либо расчетом, а 1 — показывает прогрессбар этого расчета.

K>После каждой итерации 2 вызывает функцию обработчик, которая увеличивает процент выполнения у прогрессбара.
K>В результате получается, что продвижение прогрессбара происходит во втором потоке, а хотелось бы, чтобы второй поток вообще не касался прогрессбара.

K>Надо переслать сообщение из второго потока в первый так, чтобы вызов функции продвижения прогрессбара был из первого потока.

K>Какие есть варианты? Платформа не обязательно win.

Твоя оконная библиотека должна предоставлять средства для асинхронной отправки сообщений из других потоков. Для Windows это будет что-то типа PostMessage(wnd, WM_USER_UPDATE_PROGRESS, progress_value, 0);


1024cores — all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[2]: Переброска сообщений между потоками
От: kvser  
Дата: 15.01.10 08:36
Оценка:
Здравствуйте, remark, Вы писали:

R>Твоя оконная библиотека должна предоставлять средства для асинхронной отправки сообщений из других потоков. Для Windows это будет что-то типа PostMessage(wnd, WM_USER_UPDATE_PROGRESS, progress_value, 0);


Если она есть
Re[3]: Переброска сообщений между потоками
От: remark Россия http://www.1024cores.net/
Дата: 15.01.10 08:43
Оценка: +1
Здравствуйте, kvser, Вы писали:

K>Здравствуйте, remark, Вы писали:


R>>Твоя оконная библиотека должна предоставлять средства для асинхронной отправки сообщений из других потоков. Для Windows это будет что-то типа PostMessage(wnd, WM_USER_UPDATE_PROGRESS, progress_value, 0);


K>Если она есть


Если у тебя есть прогрессбар контрол, то должна быть и оконная библиотека... или это консольный прогресс бар?


1024cores — all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[4]: Переброска сообщений между потоками
От: kvser  
Дата: 15.01.10 09:01
Оценка:
Здравствуйте, jazzer, Вы писали:

J>кстати, ты уверен, что хочешь апдейтить прогресс-бар на каждый чих второго потока?

нет, не уверен
J>А если он отработает слишком быстро?
он может одну операцию выполнить "мгновенно", а может и вообще не выполнить, тогда ошибка по таймауту~0.3сек

В принципе, суть я понял
Re[4]: Переброска сообщений между потоками
От: kvser  
Дата: 15.01.10 09:13
Оценка:
Здравствуйте, remark, Вы писали:

R>Если у тебя есть прогрессбар контрол, то должна быть и оконная библиотека... или это консольный прогресс бар?


консольный...но вывод я не хочу делать в потоке, который занимается расчетом.
Хотелось бы, чтобы второй поток просто каким-нть образом информировал первый об изменениях, а уже во-втором вызывались функции вывода
P.S. не обращайте внимания на формулировку "поток информировал"
Re[5]: Переброска сообщений между потоками
От: remark Россия http://www.1024cores.net/
Дата: 15.01.10 09:28
Оценка:
Здравствуйте, kvser, Вы писали:

R>>Если у тебя есть прогрессбар контрол, то должна быть и оконная библиотека... или это консольный прогресс бар?


K>консольный...но вывод я не хочу делать в потоке, который занимается расчетом.

K>Хотелось бы, чтобы второй поток просто каким-нть образом информировал первый об изменениях, а уже во-втором вызывались функции вывода
K>P.S. не обращайте внимания на формулировку "поток информировал"

Я понял, что выводить изменения из первого.
Ну как бы там ни было, передавать информацию о прогрессе можно тем же способом, каким ты будешь передавать информацию о завершении операции и результат работы (какой-то же способ уже должен быть для этого).


1024cores — all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[6]: Переброска сообщений между потоками
От: kvser  
Дата: 15.01.10 09:44
Оценка:
Здравствуйте, remark, Вы писали:

R>Я понял, что выводить изменения из первого.

R>Ну как бы там ни было, передавать информацию о прогрессе можно тем же способом, каким ты будешь передавать информацию о завершении операции и результат работы (какой-то же способ уже должен быть для этого).

Планировал так:
Операция завершена(прогресс бар показывает 100%) — количество выполненных итераций вторым потоком равно количеству переданных ему задач(одна задача — одна итерация)
Таким образом информация о завершении операции непосредственно не передается, а вычисляется
Re: Переброска сообщений между потоками
От: Кодт Россия  
Дата: 15.01.10 13:25
Оценка:
Здравствуйте, kvser, Вы писали:

K>Какие есть варианты? Платформа не обязательно win.


1) Независимый опрос статуса. Интерфейсный поток по таймеру смотрит на значение прогресса и показывает его.
Оптимизация: перерисовка прогресса только в том случае, если его значение изменилось с момента предыдущего опроса.

2) Синхронный колбек. Рабочий поток синхронно вызывает функцию обновления в контексте интерфейсного потока (пример: SendMessage).
Отвратительный способ, так как все при этом блокируются.

3) Асинхронное извещение типа очередь. (Сокет, PostMessage, и т.п.) Рабочий поток пишет в очередь, интерфейсный эту очередь слушает и реагирует.
Плохо, если поток извещений окажется слишком плотным. Потому что логика подсказывает, что обрабатывать нужно не каждое, а последнее.

4) Асинхронное извещение типа триггер. (Event). Рабочий поток взводит флаг, а интерфейсный слушает, сбрасывает и реагирует.
Проблемы возникают тогда, когда интерфейсный должен слушать несколько разнородных источников:
— очередь оконных сообщений
— сокеты
— триггеры
В винапи есть функция MsgWaitForMultipleObjects, да и вообще синхрообъекты приведены к единому знаменателю. В позиксе же придётся извращаться, хотя если это чисто консольное приложение, то можно в один select() запихать и stdin, и сокет, используемый в режиме триггера. (Наверное).

Триггер из сокета делается элементарно. Это пара (сокет-туда,квитанция-обратно).
В роли квитанции выступает или флажок, или сокет.
Отправитель смотрит, была ли посылка, и была ли квитанция. Если посылка была, а квитанция ещё нет — ничего не пишет.
Получатель ждёт посылку, и получив её, отправляет квитанцию.
http://files.rsdn.org/4783/catsmiley.gif Перекуём баги на фичи!
Re[2]: Переброска сообщений между потоками
От: Nik_1 Россия  
Дата: 15.01.10 15:18
Оценка:
Здравствуйте, jazzer, Вы писали:
J>Поток 2 пишет свой прогресс в какую-нть мелкую переменную и спокойно занимается своими делами, а поток 1 периодически, по своему расписанию, в эту переменную заглядывает, берет оттуда чиселку и рисует прогресс-бар. Всё.

По таймеры ненадо — это зло, лучше эвент.
Таймер нужел лишь если хочется сделать плавный прогрессбар, которые будет с расчитывать среднюю скорость и сам понемногу двигаться, даже если значение прогресса не поменялось между таймерами.
Re[3]: Переброска сообщений между потоками
От: jazzer Россия Skype: enerjazzer
Дата: 15.01.10 17:07
Оценка:
Здравствуйте, Nik_1, Вы писали:

N_>Здравствуйте, jazzer, Вы писали:

J>>Поток 2 пишет свой прогресс в какую-нть мелкую переменную и спокойно занимается своими делами, а поток 1 периодически, по своему расписанию, в эту переменную заглядывает, берет оттуда чиселку и рисует прогресс-бар. Всё.

N_>По таймеры ненадо — это зло, лучше эвент.

Почему зло, можно аргументировать?
У меня вот никаких проблем с таймерами нет, они живут пачкой, инициируют самые разнообразные события и друг другу не мешают (я пользуюсь boost.asio — им можно пользоваться даже если никакого io нету, просто очень удобный фреймворк для кооперативной многозадачности в одном (да и не только в одном) потоке).
Эвент — это на котором ждать надо (видимо, имеется в виду винда или condition variable)?
Эвенты могут привести к излишнему потоку ненужных апдейтов (представь, что второй поток исполняет какую-нть функцию в цикле неизвестное количество раз (ему это количество и функция отдается при создании потока) — тогда если функция долгая, а число итераций невелико, эвенты могут быть и хорошим вариантом, но если итераций очень много, а функция очень короткая — то первый поток будет дергаться слишком часто без весомой причины (ну зачем перерисовывать прогресс-бар миллион раз, по разу на итерацию, если в нем точек всего 200?). Можно, конечно, передавать дополнительно требуемый шаг, когда репортить, но это же может измениться, если юзер распахнет на весь экран окошко прогресс-бара...

N_>Таймер нужел лишь если хочется сделать плавный прогрессбар, которые будет с расчитывать среднюю скорость и сам понемногу двигаться, даже если значение прогресса не поменялось между таймерами.

Тоже вариант, кстати. Если у тебя уже есть таймер, то подобные расширения делаются гораздо проще.
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[3]: Переброска сообщений между потоками
От: bkat  
Дата: 15.01.10 17:08
Оценка:
Здравствуйте, Nik_1, Вы писали:

N_>Здравствуйте, jazzer, Вы писали:

J>>Поток 2 пишет свой прогресс в какую-нть мелкую переменную и спокойно занимается своими делами, а поток 1 периодически, по своему расписанию, в эту переменную заглядывает, берет оттуда чиселку и рисует прогресс-бар. Всё.

N_>По таймеры ненадо — это зло, лучше эвент.


Зависит от ситуации.
У меня к примеру поток генерит новые данные с частотой 1000 герц.
Если каждый раз посылать эвент, то поток GUI заколебается постоянно все обновлять.
Чтобы GUI не тормозил придется выдумывать разные стратегии
типа реагировать только на каждый сотый евент или только раз в секунду,
что в итоге может оказаться сложнее и запутаннее,
чем тупой таймер.
Ради "прогресс бара" таймер как раз весьма неплохое и простое решение.
Ну и посылка евента в другой поток тоже вещь не бесплатная...
Re[4]: Переброска сообщений между потоками
От: Nik_1 Россия  
Дата: 16.01.10 11:39
Оценка:
Здравствуйте, jazzer, Вы писали:
J>Почему зло, можно аргументировать?
Потому что это уже полуактивное ожидание получится. В случаи ивента поток ГУИ просыпается лишь тогда, когда действительно что-то поменялось и надо перерисовать прогрессбар, а с таймером возможна куча холостых просыпаний.
Re[4]: Переброска сообщений между потоками
От: Nik_1 Россия  
Дата: 16.01.10 11:40
Оценка:
Здравствуйте, bkat, Вы писали:

B>Зависит от ситуации.

B>У меня к примеру поток генерит новые данные с частотой 1000 герц.
Конкретно в этом случаи согласен, таймер лучше.
Re[5]: Переброска сообщений между потоками
От: Pzz Россия https://github.com/alexpevzner
Дата: 16.01.10 14:41
Оценка: +1
Здравствуйте, Nik_1, Вы писали:

J>>Почему зло, можно аргументировать?

N_>Потому что это уже полуактивное ожидание получится. В случаи ивента поток ГУИ просыпается лишь тогда, когда действительно что-то поменялось и надо перерисовать прогрессбар, а с таймером возможна куча холостых просыпаний.

Ну если эти холостые просыпания происходят 1-2 раза в секунду, то практических проблем это не создает, а код становится проще.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.