Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Как усыпить поток. [D7, WinXP]


Страницы:   1 2 3 4 5

Kolan ©   (2006-02-06 21:50:00) 

Здравствуйте,
 Много раз слышал при обсуждении работы с потоками
"если то-то то поток засыпает, если еще что-то то просыпается..."

А как это. Можно пример усыпления.
Я просто проверяю какое-нибудь условие и если потоку делать нечего делаю например Sleep(1). А иначе загрузка процессора на 97% - 99%


Digitman   (2006-02-08 17:47:00) [21]


> Eraser ©   (08.02.06 17:25) [68]


Общий ресурс для транспортного и обрабатывающего тредов в случае автора - один единственный буфер (или поток). Зачем ему куча КС, когда речь пока идет об одном-единственном ресурсе ?


Eraser   (2006-02-08 17:25:00) [22]


> evvcom ©   (08.02.06 15:40) [66]

насчёт крит. секций - не пробовал, в вот точно такое решение, но на мьютексах работает.

> Digitman ©   (08.02.06 15:49) [67]


> Ты хоть сам в состоянии кратко и внятно сказать, какая из
> трех крит.секций у тебя какой ресурс защищает ?

1 поток - считывание данных
EnterCriticalSection(cs1); // пробуем "войти" в первую крит. секцию, если не удаётся - значит ещё не обработан предыдущий буфер (пакет данных) - ждём
EnterCriticalSection(cs3); // т.к. буфер у нас один - защищаем его на момент записи в него данных
заполняем буффер, предварительно считанными данными;
LeaveCriticalSection(cs3);
LeaveCriticalSection(cs2); // второй поток может приступать к считыванию буфера

2 поток - обработака данных

EnterCriticalSection(cs2);
EnterCriticalSection(cs3);
обрабатываем данные, кторые в буффере;
LeaveCriticalSection(cs3);
LeaveCriticalSection(cs1); // буфер обработан (или сохранён для послудующей обработки за критической секцией)! разреаем первому потоку писать слеудющую порцию данных

На базе семафоров можно смастерить таким образом n-ю буфферизацию.


Digitman   (2006-02-08 15:49:00) [23]


> Eraser ©   (08.02.06 13:56) [64]


Ну и куда ты их, крит.секций, наплодил столько ?

Ты хоть сам в состоянии кратко и внятно сказать, какая из трех крит.секций у тебя какой ресурс защищает ?


evvcom   (2006-02-08 15:40:00) [24]


> А задачи синхронного чтения/обработки данных решается "взаимопересекающимеся"
> критическими секциями
> EnterCriticalSection(cs 2);
> LeaveCriticalSection(cs 1);

Интересное решение. И что? Думаешь будет работать?


Digitman   (2006-02-08 14:47:00) [25]


> Стрим это -TMemoryStream?


Да.


> Что будет если обрабатывающий поток занял её. А транспортный
> получил байты и пытается тоже занять её. Байты не пропадут?
>


Нет, не пропадут.

Когда обрабатывающий тред закончит обработку очередных данных в стриме и выйдет из крит.секции, в нее тут же войдет транспортный тред (все это время покорно ждавший освобождения занятой трансп.потоком крит.секции) и наполнит стрим новыми данными ..


Eraser   (2006-02-08 13:56:00) [26]

ещё одно уточнение!
var
cs1, cs2, cs3: TКритическаяСекция;
buf: Буффер;
...
инициализируем крит. секции.

1 поток - считывание данных

чтобы код работал эффективно считываем данные из портма
здесь! т.к. перед крит. секциями!
EnterCriticalSection(cs1);
EnterCriticalSection(cs3);
заполняем буффер, предварительно считанными данными;
LeaveCriticalSection(cs3);
LeaveCriticalSection(cs2);

2 поток - обработака данных

EnterCriticalSection(cs2);
EnterCriticalSection(cs3);
обрабатываем данные, кторые в буффере;
LeaveCriticalSection(cs3);
LeaveCriticalSection(cs1);


Eraser   (2006-02-08 13:38:00) [27]

пардон.

var
cs1, cs2, cs3: TКритическаяСекция;
buf: Буффер;
...
инициализируем крит. секции.

1 поток - считывание данных

EnterCriticalSection(cs1);
EnterCriticalSection(cs3);
считываем данные в буффер;
LeaveCriticalSection(cs3);
LeaveCriticalSection(cs2);

2 поток - обработака данных

EnterCriticalSection(cs2);
EnterCriticalSection(cs3);
обрабатываем данные, кторые в буффере;
LeaveCriticalSection(cs3);
LeaveCriticalSection(cs1);


Eraser   (2006-02-08 13:37:00) [28]


> Kolan ©

скажу и своё имхо.
Думаю поток данных с COM порта не на чтолько велик, чтобы надо было создавать какие-то дуфера для его обработки.
А задачи синхронного чтения/обработки данных решается "взаимопересекающимеся" критическими секциями (или же соотв. объектами ядра). Примерно так.
Схаматично.

var
 cs1, cs2, cs3: TКритическаяСекция;
 buf: Буффер;
...
инициализируем крит. секции.

1 поток - считывание данных

EnterCriticalSection(cs 1);
EnterCriticalSection(cs 3);
считываем данные в буффер;
EnterCriticalSection(cs 3);
LeaveCriticalSection(cs 2);

2 поток - обработака данных

EnterCriticalSection(cs 2);
EnterCriticalSection(cs 3);
обрабатываем данные, кторые в буффере;
EnterCriticalSection(cs 3);
LeaveCriticalSection(cs 1);

впринципе к такой схеме можно и двойную-тройную и т.д. буфферизацию не сложно приделать.


Kolan   (2006-02-08 13:22:00) [29]


> - по событию приема принимает из порта данные (сколько бы
> их ни было принято - хоть один хоть косой десяток)


Вот так сейчас и есть.
Попробую сделать ваш вариант.
Стирим это - TMemoryStream?
Просто с этим не работал. Надо изучить...

С крит секциями у меня проблеммы т.к. я неточно понимая логику их работы.

Что будет если обрабатывающий поток занял её. А транспортный получил байты и пытается тоже занять её. Байты не пропадут?

А если эта ситуация неск раз подрад будет. Те приходит допустим 3 массива из порта. Все патаются заити в кс, а она занята.

Когда она освободится что будет?..

Буду пытатся сделать :)

Еще раз благодарю за подсказки. Оч. интересно и позновательно :)


Digitman   (2006-02-08 12:25:00) [30]


> Leonid Troyanovsky ©   (08.02.06 12:17) [59]


> "уплотнять" данные лучше тогда, когда очередь пуста


Можно и так.


Leonid Troyanovsky   (2006-02-08 12:17:00) [31]


> Digitman ©   (08.02.06 12:09) [57]

> 4. извлекает из стрима очередной обнаруженный пакет, корректирует
> (уменьшает) размер стрима и св-во Position на величину извлеченного
> пакета (оставшиеся в стриме данные сдвигаются в начало стрима)


IMHO, "уплотнять" данные лучше тогда, когда очередь пуста.
Ну, и делать это так, чтобы пришедший запрос мог сразу
прервать оное занятие.

--
Regards, LVT.


Digitman   (2006-02-08 12:16:00) [32]


> Больше всего меня беспокоет то, что потоки как бы общаются
> через главный,
> вызавая соотв. события с Synchronize


Если беспокоит, то есть повод для предметного и детального анализа такой необходимости.


Digitman   (2006-02-08 12:09:00) [33]


> Итак у меня 3 потока


Один из 3-х, imho, явно лишний.. "дармоед" он)

Я все же настаиваю на реализации со стримом, а не с кольц.буфером.

Поток 1 (транспортный) работает с портом :

- по событию приема принимает из порта данные (сколько бы их ни было принято - хоть один хоть косой десяток), убирает если нужно упр.символы, входит в крит.секцию, записывает принятое в стрим (св-во Position увеличивается на размер записанных данных), устанавливает event, выходит из крит.секции

Поток 2 (обрабатывающий)  в цикле с проверкой на Terninated:

1  Спит, ожидая сигнал event'а
2. по сигналу event'а просыпается, входит в крит.секцию,
3. анализирует имеющиеся на сей момент в стриме данные на предмет наличия хотя бы одного целостного пакета, если такового нет, то сбрасывает event и идет на 7.
4. извлекает из стрима очередной обнаруженный пакет, корректирует (уменьшает) размер стрима и св-во Position на величину извлеченного пакета (оставшиеся в стриме данные сдвигаются в начало стрима)
5. обрабатывает пакет нужным образом и идет на 3.
7. Выходит из крит секции, идет на 1.


Kolan   (2006-02-08 11:39:00) [34]

evvcom ©   (08.02.06 08:39) [46]

Кроме выше описанных потоков есть поток, который проверяет очередь порта, если они есть вызывает событие:

procedure TForm1.ReadFromComm(Sender: TObject; ReadBytes: array of Byte);
begin
 FPackageExtractor.AddBayteArray(ReadBytes);
 StatusBar1.Panels[2].Text  := 'Ïîëó÷åííî áàéò: '
   + IntToStr(Length(ReadBytes)) + '.';
end;


1. Ждать активности COM порта.
2. Считать байт, если не управляющий символ - то записать в буфер и сместить индекс.
3. Если символ "старта" - запонить позицию старта пакета.
4. Если символ "стопа" - (для начала можно расчитать CRC) начиная с запомненной позиции старта скопировать данные по текущую позицию и положить в очередь принятых пакетов, оповестить транспортный уровень о том, что был получен очередной пакет очередной пакет.
5. Goto 1.


2. Чтение по 1 байту критично ка я понял?

Итак у меня 3 потока

1. Тот что читает из порта. Он вызовет событие при получении 1 байта.
Тут ничего не меняю

2. По возникновении этого события, основной поток этот байт кладет в кольцевой буффер.
И устанавливает Event.

3. В свою очередь поток, выделяющий пакеты, просыпается по Eventи выполняет проверку(она у меня есть, тут тоже не меняю ничего?)

4. Прочитав байт он сравнивает индексы(они равны) и сбрасывает Event.

5. Обнаружив пакет он копирует его из кольц. буффера, обнуляет индексы, сбрасывает Eventи через событие вызываемое через гл поток(как в п.2) кладет этот массив в очередь потока №3. Устанавливаепт его
Event2.

6. Тот поток прсыпается и пока очередь непуста парсит пакеты вызывая соотв событие, когда пакет распарсен...

Господи помоги мне понять где тут что надо зашитить и как... :)

Благодарю за помощь. :)
Правильно ли я понял идею?

Больше всего меня беспокоет то, что потоки как бы общаются через главный,
вызавая соотв. события с Synchronize. Может на прямую можно. Как?


Digitman   (2006-02-08 10:47:00) [35]


> Defunct ©   (08.02.06 10:38) [54]


Что ж ...
Вполне нормальное решение.


Defunct   (2006-02-08 10:38:00) [36]

Digitman ©   (08.02.06 10:21) [53]
По сути автор как раз и пытается приспособить массив для работы в кач-ве стрима. Но массив этот имеет фикс.размер, и  если обрабатывающий тред не будет поспевать за транспортным (что не так уж и маловероятно), то рано или поздно возникнет ситуация либо выхода индекса записи за пределы верх.границы массива либо потери инф-ции в случае использования массива транспортным тредом в кач-ве кольц.буфера.

Да Вы правы в том, что так как эту задачу пытается решить автор (обращаться к одному и тому же массиву на канальном и транспортном уроване) возможны проблемы.

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

1. Ждать активности COM порта.
2. Считать байт, если не управляющий символ - то записать в буфер и сместить индекс.
3. Если символ "старта" - запонить позицию старта пакета.
4. Если символ "стопа" - (для начала можно расчитать CRC) начиная с запомненной позиции старта скопировать данные по текущую позицию и положить в очередь принятых пакетов, оповестить транспортный уровень о том, что был получен очередной пакет очередной пакет.
5. Goto 1.

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


Digitman   (2006-02-08 10:21:00) [37]


> Defunct



> а смысл? добавить еще одну заботу очистки/контроля размера
> потока?


Забота треда транспортного уровня - писать в стрим все что принято (с уведомлением обрабатывающего треда о факте очередной записи в стрим).

Забота обрабатывающего треда - читать из стрима, распознавать пакеты, извлекать их из стрима (с соотв. коррекцией его размера и позиции записи) и обрабатывать.

Все !
И никаких кольц.буферов.

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


Defunct   (2006-02-08 10:07:00) [38]

> Для принимающего трэда это обычный аккумулирующий поток.
> А раз поток, то гораздо логичней было бы вместо массива использовать TStream-наследника, например, TMemoryStream


а смысл? добавить еще одну заботу очистки/контроля размера потока?


Defunct   (2006-02-08 10:00:00) [39]

Digitman ©   (08.02.06 09:49) [49]

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


Digitman   (2006-02-08 09:57:00) [40]

Да и не кольцевой это буфер при ближайшем рассмотрении..
Для принимающего трэда это обычный аккумулирующий поток.
А раз поток, то гораздо логичней было бы вместо массива использовать TStream-наследника, например, TMemoryStream


Страницы:   1 2 3 4 5

Наверх

Титульная страница Поиск, карта сайта Написать письмо