![]() |
|
Модераторы: bsa |
![]()
|
|
| OpenMan |
|
|||
|
Новичок Профиль Группа: Участник Сообщений: 48 Регистрация: 19.4.2009 Репутация: нет Всего: 1 |
Задача такова:
Есть поток А, который делает что-то с данными. И есть другие потоки Б, которые приносят новые данные. Потоки Б между собой синхронизированны на предмет приноса новых данных. Как я понимаю, если есть данные то поток А должен работать, если этих данных нет, то поток должен спать до тех пор, пока не появятся новые данные. Тока никак не пойму как это можно реализовать. Поток Б. добавил данные; isNewData = true; // синхронизация + if(isSleep){ возобновляем поток А } // синхронизация - Поток А while(true){ if(isNewData){ isNewData = false; действие с данными новыми continue; } else{ // синхронизация + isSleep = true; // синхронизация - усыпляем поток А isSleep = false; } } прошу прощения за псевдокод и за то, что оформил не в рамке. Проблема вот в чем, возможна такая ситуация, когда поток А проверит и убедиться, что нет новых данных, установит флаг isSleep, в это же время поток Б добавит новые данные, посмотрит, что поток А вырублен (isSleep==true), и постарается его возобновить, а после этого поток А уснет. Получится, что с одной стороны поток вырублен, а с другой стороны флаг isSleep равен false. по понятным причинам включить инструкцию "усыпляем поток А" внутрь синхронизированного блока не получиться. Как быть? Один из вариантов - это пытаться восcтановить поток вне зависимости от флага isSleep. Но в этом случае получиться громадная дополнительная нашрузка на ЦП, Ведь новые данные поступают много маленькими кусочками, и время на обработку каждого мало, а операция восстановления потока не быстрая (как я понимаю). Получиться, что 80% ЦП будет уходить на избыточную "возобновляем поток А". Есть ещё вариант вместо приостанавливании потока используем Sleep(50) (на время); Но в этом случае возможен вариант, когда данные будут ждать 50 милсек, а мне надо как можно раньше данные обработать. Ставить Sleep(5) - опять же зря напрягать центральный процессор. Как люди в таких ситуациях поступают? Чую должен быть какой-то паттерн на этот случай. Добавлено через 8 минут и 30 секунд Пардон, глупость сморозил. С флагами все правильно... Но сама проблема остаётся. Новые данные могут быть добавлены, но после "восстановления потока А", может случиться "усыпляем поток А", и таким образом, данные буду не обработаны до прихода следующих данных, что не хорошо. |
|||
|
||||
| bsa |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 9185 Регистрация: 6.4.2006 Где: Москва, Россия Репутация: 85 Всего: 196 |
OpenMan, почитай про семафоры. Т.е. это такой тип переменной, которую один из потоков увеличивает, а другой уменьшает. Если она равна нулю, а ее попробует уменьшить второй, то он засыпает до тех пор, пока первый не увеличит.
|
|||
|
||||
| OpenMan |
|
|||
|
Новичок Профиль Группа: Участник Сообщений: 48 Регистрация: 19.4.2009 Репутация: нет Всего: 1 |
Примерно я представляю, что это такое. Только как это может помочь?
Собственно, как я понимаю семафоры отличаются от критических секций только тем, что у критических секций может выполняться только 1 поток. Фишка в том, что нужно, чтобы после того как поток Б выходит из своей зоны (оставил данные), поток А проснулся если спал. Уже минут 20 думаю. но не понимаю что тут могут дать семафоры. |
|||
|
||||
| OpenMan |
|
|||
|
Новичок Профиль Группа: Участник Сообщений: 48 Регистрация: 19.4.2009 Репутация: нет Всего: 1 |
Попробую поставить задачу более абстрактно.
Есть Пекать который печет булки используя муку. Условно из одного мешка получается 1 булка. И есть много слуг, которые приносят муку к пекарю. Поведение пекаря: если есть мука в наличии, то берем 1 мешок и делаем 1 булка, далее проверяем есть ли ещё мука и так далее. Если после очередной работы пекарь не обнаруживает муку, то он ложится спать. Поведение слуги. пришел, положил мешок, если пекарь спит, то будим пекаря. Сейчас я описал стандартную задачу "с буффером" и обрабатывающим этот буфер потоком. Как мне кажется такая задача встречается много где. В чем загвостка, а в том, что у пекаря " проверить склад муки и заснуть" - это 2 команды, и межу ними может много чего произойти. Что может произойти? пекарь допекает свою последнюю булку, проверяет пуст ли склад, убеждается, что пуст, .... в это время приходит слуга, кладет новый мешок, будит пекаря (пекарь ещё не спит), и уходит. А в это время пекарь приступает к команде спать. Таким образом мешок на складе есть, а пекарь спит, и будет спать пока не придет следующий слуга. Обычно подобные вещи решаются объединением 2-х команд в одну критическую секцию. Но по понятным причинам нельзя в такую секцию засунуть команду "спать", иначе поток заснет и секция будет занята, и никто не сможет разбудить пекаря. Желательно, чтобы пекарь работал 1) Оперативно,т.е. если мука есть, он должен в тот час же приступать к работе, в пределах времени требуемой на пробуждение. 2) Минимально, т.е. спал если муки нет. |
|||
|
||||
| vnf |
|
|||
|
Шустрый ![]() Профиль Группа: Участник Сообщений: 51 Регистрация: 9.2.2008 Репутация: нет Всего: 1 |
А почему используете sleep? Неподходяще.
Тут надо использовать функции ожидания и семафор (выше предлагали). |
|||
|
||||
| OpenMan |
|
|||
|
Новичок Профиль Группа: Участник Сообщений: 48 Регистрация: 19.4.2009 Репутация: нет Всего: 1 |
Можно шаблон того, как прикрутить сюда семафоры. В упор не вижу как с помощью них решить проблему.
Нет, я в основном использую wait() под словом спать. Не правильно выразился я. |
|||
|
||||
| bsa |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 9185 Регистрация: 6.4.2006 Где: Москва, Россия Репутация: 85 Всего: 196 |
OpenMan, вот смотри, пекарь уменьшает семафор, слуга увеличивает. в чем проблема? Все давно уже решено.
|
|||
|
||||
| OpenMan |
|
|||
|
Новичок Профиль Группа: Участник Сообщений: 48 Регистрация: 19.4.2009 Репутация: нет Всего: 1 |
Немного усложним вопрос.
Как я понимаю под виндой единственный способ использования семафоры - это всякие там hSemaphore = CreateSemaphore( NULL, // нет атрибута cMax, // начальное состояние cMax, // максимальное состояние NULL // без имени ); Задача немного меняется, теперь пекарь может забирать сразу до 10 мешков, если они есть. Освобождать можно любое количество с помощью ReleaseSemaphore( Semaphore,N,0) а вот опускать как это дело? пекарь() { do { sem_wait(sem); //спать, пока нет мешков pthread_mutex_lock(mutex); //входим в критическую секцию взятия мешка n =взять до 10 мешоков pthread_mutex_unlock(mutex); //выходим из критической секции взятия мешка печь булки for(int i=1; i<n; i++){ sem_wait(sem); } } while(1); } Так что ли? Ведь в указанном вами способе 1 значение семафора равняется ровно 1 мешку. |
|||
|
||||
| xvr |
|
|||
|
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 7046 Регистрация: 28.8.2007 Где: Дублин, Ирландия Репутация: 35 Всего: 223 |
Нет
|
|||
|
||||
| Acer |
|
|||
![]() Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 652 Регистрация: 5.9.2007 Где: UA::DN Репутация: нет Всего: 8 |
bsa, а в данной задаче можно использовать ту же переменную isSleep, только если обьявить ее как volatile?
|
|||
|
||||
| bsa |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 9185 Регистрация: 6.4.2006 Где: Москва, Россия Репутация: 85 Всего: 196 |
volatile не значит atomic. В многопоточных программах можно использовать только атомарные операции с общими данными. Иначе race condition.
|
|||
|
||||
| OpenMan |
|
|||
|
Новичок Профиль Группа: Участник Сообщений: 48 Регистрация: 19.4.2009 Репутация: нет Всего: 1 |
как я понимаю, аналог используемого sem_trywait(sem) в ВинАПИ - это WaitForSingleObject(sem, 0)
с проверкой возвращенного значения на равненство 0. Почему так for(;i<10;++i) if (sem_trywait(sem)) break; не получится в моем случае, потому в моей задачи несколько различных "складов". Поэтому придется хранить количество мешков на каждом складе по отдельности и уменьшать\увеличивать при взятии. Скажем так, первый склад - это обязательная очередь, у которой наивысший преоритет, а остальные - это ограниченные FIFO по размеру (например предел 3 мешка, если добавляется 4-й, то первый выкидывается) соответственно со средним преоритетом (если обязательная очередь пуста) и наименьшем. Просто как-то странно, что функциия ReleaseSemaphore может увеличивать счетчтк на любое количество, в то время как, уменьшать можно только на единицу. А в обшем спасибо. |
|||
|
||||
| xvr |
|
|||
|
Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 7046 Регистрация: 28.8.2007 Где: Дублин, Ирландия Репутация: 35 Всего: 223 |
|
|||
|
||||
![]()
|
| Правила форума "C/C++: Для новичков" | |
|
|
Запрещается! 1. Публиковать ссылки на вскрытые компоненты 2. Обсуждать взлом компонентов и делиться вскрытыми компонентами
Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, JackYF, bsa. |
| 0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей) | |
| 0 Пользователей: | |
| « Предыдущая тема | C/C++: Для новичков | Следующая тема » |
|
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |