![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Как усыпить поток. [D7, WinXP]
Kolan © (2006-02-06 21:50:00)Здравствуйте,
Много раз слышал при обсуждении работы с потоками
"если то-то то поток засыпает, если еще что-то то просыпается..."
А как это. Можно пример усыпления.
Я просто проверяю какое-нибудь условие и если потоку делать нечего делаю например Sleep(1). А иначе загрузка процессора на 97% - 99%
Digitman (2006-02-08 09:49:00) [41]
> отказываться от кольцевого буфера в принимающем потоке -
> не стоит
Тогда потери пакетов не исключены.
Defunct (2006-02-08 09:43:00) [42]
> Digitman © (08.02.06 09:20) [47]
> Если так, то использование массива в кач-ве очереди вряд ли оправдано.
нет, у него там немного иная задача.
Один поток обслуживает канальный уровень по приему пакетов от некоего устройства через COM порт. Второй поток должен обрабатывать уже готовые пакеты. Очередь (TQueue) можно использовать в качестве согласующего звена между первым и вторым потоком, но вот отказываться от кольцевого буфера в принимающем потоке - не стоит.
Digitman (2006-02-08 09:20:00) [43]
> Kolan © (07.02.06 20:58) [45]
Насколько я понял, тебе требуется реализовать следующее :
Есть некая очередь данных, требующих обработки.
Один код.поток (1) помещает данные по мере их формирования в хвост очереди, другой код.поток (2) извлекает данные из головы очереди и обрабатывает их (либо "спит" если очередь пуста).
Если так, то использование массива в кач-ве очереди вряд ли оправдано.
Например, есть готовый класс TQueue, реализующий логику очереди. Можно защитить доступ к методам/св-вам его экз-ра крит.секцией, при добавлении в хвост очереди устанавливать событие (SetEvent), при опустошении очереди сбрасывать событие (ResetEvent).
Поток 1, добавляя очередной элемент (или несколько очередных элементов) в хвост, "сигналит" об этом установкой события. Поток 2 "просыпается" по этому сигналу и начинает циклически выбирать элементы из головы и обрабатывать их, до тех пор пока не обнаружит опустошение очереди, после чего вновь "засыпает", сбросив непосредственно перед этим событие в несигналящее состояние.
evvcom (2006-02-08 08:39:00) [44]Это же не весь код. AddArray только описан, но где вызывается не ясно. В коде доступ к FWriteIndex, FReadIndex осуществляется из всех этих 3-х методов. Execute и MakeAndSendPackage синхронизированы, а AddArray не ясно.
FWriteIndex <> FReadIndex - это тоже доступ.
> Те весь этот if надо зашитить?
Все зависит от того, синхронизированы ли уже доступы из разных потоков.
Kolan (2006-02-07 20:58:00) [45]Спасибо за ответ. Завтра разберусь....
:)
Defunct (2006-02-07 19:30:00) [46]> Kolan
Почитайте последний пост, в вашей предыдущей ветке.
Kolan (2006-02-07 17:44:00) [47]Я непонял
if (FState <> sIdle) and (FWriteIndex <> FReadIndex) then
Это же тоже доступ?
Те весь этот if надо зашитить?
Digitman (2006-02-07 17:15:00) [48]
> Kolan © (07.02.06 16:46) [41]
Эта логика ведет к непредсказуемым (печальным) последствиям...
Доступ к массиву и тем самым индексам в нем должен быть защищен крит.секцией.
Kolan (2006-02-07 16:46:00) [49]Индыксы обнулятся только если состояние
sIdleи доп поток гарантированно не использует эти переменные
Вообщем вот полный код:
procedure TPackageExtractThread.AddArray(Arr: array of Byte);
var
I, J: Longint;
begin
if FState = sIdle then
begin
FWriteIndex := 0;
FReadIndex := 0;
end;
J := FWriteIndex;
for I := Low(Arr) to High(Arr) do
begin
FBuffer[J] := Arr[I];
J := J + 1;
end;
FWriteIndex := J;
if FState = sIdle then
begin
FState := sWaitForStart;
end;
end;
procedure TPackageExtractThread.Execute;
begin
FreeOnTerminate := True;
while not Terminated do
begin
if (FState <> sIdle) and (FWriteIndex <> FReadIndex) then
begin
case FState of
sWaitForStart:
begin
if (FBuffer[FReadIndex] = StartByte) then
begin
FState := sWaitForEnd;
FStartIndex := FReadIndex;
end;
FReadIndex := FReadIndex + 1;
end;
sWaitForEnd:
begin
if (FBuffer[FReadIndex] = EndByte) then
begin
FState := sEndFound;
end;
FReadIndex := FReadIndex + 1;
end;
sEndFound:
begin
if (FBuffer[FReadIndex] <> EndByte) then
begin
FState := sPackegeReady;
FReadIndex := FReadIndex - 1;
end
else
begin
FState := sWaitForEnd;
end;
FReadIndex := FReadIndex + 1;
end;
sPackegeReady:
begin
FEndIndex := FReadIndex;
FState := sIdle;
Synchronize(MakeAndSendPackage);
end;
end;
end
else
begin
Sleep(1);
end;
end;
end;
procedure TPackageExtractThread.MakeAndSendPackage;
var
I, J: Longint;
Answer: array of Byte;
begin
SetLength(Answer, (FEndIndex - FStartIndex) + 1);
J := Low(Answer);
for I := FStartIndex to FEndIndex do
begin
Answer[J] := FBuffer[I];
J := J + 1;
end;
FState := sIdle;
FReadIndex := 0;
FWriteIndex := 0;
FPackageReadyEvent(Self, Answer);
end;
Digitman (2006-02-07 16:42:00) [50]
> А что будет ошибка если один поток сделает
> FWriteIndex := J;
> А второй в этоже время проверит
> if (FState <> sIdle) and (FWriteIndex <> FReadIndex) then
> ?
Бардак будет.
Kolan (2006-02-07 16:40:00) [51]Kolan © (07.02.06 14:19) [20]
Вопрос такой: Если я уже сделал SetEvent и сделаю ео повторно - что будет?
Я это не просто так спрашивал. Я сначала все позашишал кр. секциями...
Возникала сит когда я дважды делалReleaseи потомAcquireуже не вызывался. Как проверить тек сост кр. секции я ненашел...
Поэтому переделал без кс.
А что будет ошибка если один поток сделает
FWriteIndex := J;
А второй в этоже время проверит
if (FState <> sIdle) and (FWriteIndex <> FReadIndex) then
?
Digitman (2006-02-07 16:36:00) [52]
> Когда поток нашел покет, он вызовет процедуру передач и
> пакета и обнулит индекс ы. Не пойму где они пересекутся
> Доп поток изменяет только индекс чтения
"Как тебя понимать, Саид ?" (с)
Kolan (2006-02-07 16:32:00) [53]Доп поток изменяет только индекс чтения. Гл поток изменяет индекс записи.
Причем если состояние Idle(те доп поток не работает) обнуляет индексы.
Когда поток нашел покет, он вызовет процедуру передач и пакета и обнулит индексы. Не пойму где они пересекутся.
Или если один поток пишет по индексу A а второй по индексу B одного и тогоже массива(причем точно индексы разные) - будет ошибка?
Скажите - это может повлиять на правильность работы с Event. Те из - за чего межет засыпать...
evvcom (2006-02-07 16:28:00) [54]
> Ведь записываю и читаю всегда по разным индексам
Ты сами переменные читаешь и пишешь в разных потоках, уже это надо синхронизировать.
Digitman (2006-02-07 16:16:00) [55]
> Может я и неправ
с учетом
> изменяют их главный и доп поток
оч даже неправ !
Kolan (2006-02-07 16:13:00) [56]
Да уж .. где синхронизация-то ? доступа к этим данным ?
Нету
Я думая она ненужна... Ведь записываю и читаю всегда по разным индексам...
Может я и неправ.
Вообщето она была, но я убрал ее...
А если Write на круг обогнал Read?
Нет такое невозможно... Если по идее до конца массива они не дойдут( если дойдут массив увеличу...)
Digitman (2006-02-07 15:33:00) [57]
> Kolan © (07.02.06 15:00) [28]
Да уж .. где синхронизация-то ? доступа к этим данным ?
evvcom (2006-02-07 15:09:00) [58]
> FReadIndex как бы догоняет FWriteIndex если они сравнялись,
> то жду пока еще добавят байты
А если Write на круг обогнал Read?
evvcom (2006-02-07 15:07:00) [59]
> Но изменяют их главный и доп поток...
Что-то в твоем коде синхронизации доступа к ним не видно... :( Очень подозрительна фраза "все работает"
Kolan (2006-02-07 15:06:00) [60]Извените, отвечу позже :)