![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Как усыпить поток. [D7, WinXP]
Kolan © (2006-02-06 21:50:00)Здравствуйте,
Много раз слышал при обсуждении работы с потоками
"если то-то то поток засыпает, если еще что-то то просыпается..."
А как это. Можно пример усыпления.
Я просто проверяю какое-нибудь условие и если потоку делать нечего делаю например Sleep(1). А иначе загрузка процессора на 97% - 99%
Eraser (2006-02-10 15:26:00) [1]
> evvcom © (10.02.06 09:24) [88]
хм... действительно я допустил ошибку, предлжив использовать крит. секции...
After a threadhas ownership of a critical section, it can make additional calls to EnterCriticalSection or TryEnterCriticalSection without blockingits execution. This prevents a thread from deadlocking itself while waiting for a critical section that it already owns.
В своём проекте я использовать сходную схему, НО только применял семафоры... WaitForSingleObject работает по-другому.
evvcom (2006-02-10 09:24:00) [2]
> мешает следующая интерация цикла в потоке. Т.е. цикл не будет выполнятся далее,
Бред. Напиши в тексте программы 10 раз друг за другом EnterCriticalSection(cs1); и посмотри, что получится.
Eraser (2006-02-09 20:08:00) [3]
> evvcom © (09.02.06 14:24) [85]
> В твоем коде ничто не мешает войти в cs1.
Мешает! А именно мешает следующая интерация цикла в потоке. Т.е. цикл не будет выполнятся далее, если буфер не обработан. В том то и "фишка".
Defunct (2006-02-09 15:39:00) [4]> Kolan
да не за что, мне не жалко,
напротив, спасибо вам за заинтересовавший меня вопрос. ;>
evvcom (2006-02-09 14:24:00) [5]1 поток - считывание данных
EnterCriticalSection(cs1); // пробуем "войти" в первую крит. секцию, если не удаётся- значит ещё не обработан предыдущий буфер (пакет данных) - ждём
В твоем коде ничтоне мешает войти в cs1.
LeaveCriticalSection(cs2); // второй поток может приступать к считыванию буфера
Какой смысл покидать cs2, если поток в нее и не входил? И также ничтоне мешает 2-му потоку повторно войти в cs2. Далее по тексту аналогично.
Kolan (2006-02-09 12:54:00) [6]Defunct © (09.02.06 12:20) [83]
Очень признателен за помощь :). Даже неудобно что вы так помогаете :)...
Defunct (2006-02-09 12:20:00) [7]Kolan © (09.02.06 12:11) [82]
У меня там есть ошибка (поспешил выложить код, не проперив надлежащим образом).
после вот этой строки:
FPacketSize := FAccumulatedPacketLength - 1;
необходимо сбросить
FAccumulatedPacketLength := 0;
Kolan (2006-02-09 12:11:00) [8]Благодарю. Я правда не мучался. Обязательно разберу ваш код.
Просото я стараюсь разобраться сам. Тем более пока время есть...
Я ж еще только учус (С)
:)
Defunct (2006-02-09 11:57:00) [9]Я уже не могу смотеть на то, как вы мучаетесь.. Написал прототип класса работающего в вашем протоколе..
unit uChannel;
interface
{$define DemoMode}
uses SysUtils, SyncObjs
{$ifdef DemoMode}, Dialogs {$endif}
;
const protoPACKETSTART = $AC; // Символ старта пакета
protoPACKETSTOP = $A5; // Символ стопа
protoMAXPACKETLENGTH = 2048; // Максимальная длина пакета
protoCW : set of byte = [protoPACKETSTART, protoPACKETSTOP];
rsSIZE = protoMAXPACKETLENGTH * 2;
type
TDataChannel = class( TObject )
private
// секция обслуживания кольцевого буфера
FRing : array[0..rsSIZE -1] of byte;
FRingIndex : Integer;
FStartIndex : Integer;
FLastValue : Byte;
FMonitorPacket : boolean;
FAccumulatedPacketLength : Integer;
procedure AddToRing( Value : byte );
function StartCondition(Value : byte):boolean;
function StopCondition(Value : byte):boolean;
function GetPacketByteIndex( Offset : integer ):integer;
protected
// секция обслуживания событий
FEvent : TEvent;
procedure NotifyNextLayer;virtual;
protected
// секция обслуживания пакетов
FPacket : array[0..protoMAXPACKETLENGTH] of byte;
FPacketSize : integer;
function CheckCRC:boolean;virtual;
public
procedure AddByte( Value : byte );
constructor Create( APacketReceptionEvent : TEvent);
destructor Destory;virtual;
end;
implementation
{ TDataChannel }
constructor TDataChannel.Create(APacketReceptionEvent: TEvent);
begin
FEvent := APacketReceptionEvent;
FRingIndex := 0;
FMonitorPacket := false;
end;
procedure TDataChannel.AddByte(Value: byte);
var
i : integer;
begin
if StartCondition( Value ) then
begin
FStartIndex := FRingIndex;
FMonitorPacket := True;
FAccumulatedPacketLength := 0;
end
else if StopCondition( Value ) then
begin
if FMonitorPacket then // пакет принят
begin
FMonitorPacket := false;
FPacketSize := FAccumulatedPacketLength - 1;
for i := 0 to FPacketSize do
FPacket[ i ] := FRing[ GetPacketByteIndex(i) ];
if CheckCRC then // Пакет распознан и CRC верная
begin // Оповещаем обработчик пакета
NotifyNextLayer;
{$ifdef DemoMode}
// В Демо режиме ВЫВОДИМ НА ЭКРАН ИНФОРМАЦИЮ О ПОЛУЧЕННОМ ПАКЕТЕ
ShowMessage( Format('Принят и распознан пакет, длина = %D',[FPacketSize]) );
{$endif}
end
end;
end;
AddToRing( Value );
end;
function TDataChannel.StartCondition(Value: byte): boolean;
begin
Result := (FLastValue = protoPACKETSTART) and (Value <> protoPACKETSTART)
end;
function TDataChannel.StopCondition(Value: byte): boolean;
begin
Result := (FLastValue = protoPACKETSTOP) and (Value <> protoPACKETSTOP)
end;
function TDataChannel.GetPacketByteIndex(Offset: integer): integer;
begin
Result := Offset + FStartIndex;
if Result >= rsSIZE then
Result := Result - rsSIZE;
end;
procedure TDataChannel.AddToRing(Value: byte);
begin
if (Value in protoCW) and (Value = FLastValue) then
begin
FLastValue := 0;
exit;
end;
FRing[ FRingIndex ] := Value;
FLastValue := Value;
inc( FRingIndex );
if FRingIndex = rsSIZE then
FRingIndex := 0;
if FMonitorPacket then
begin
Inc( FAccumulatedPacketLength );
if FAccumulatedPacketLength > protoMAXPACKETLENGTH then
begin
FAccumulatedPacketLength := 0;
FMonitorPacket := false;
end;
end;
end;
function TDataChannel.CheckCRC: boolean;
begin
{ abstract CRC function }
Result := True
end;
procedure TDataChannel.NotifyNextLayer;
begin
{ abstract procedure }
if Assigned( FEvent ) then
FEvent.SetEvent
end;
destructor TDataChannel.Destory;
begin
inherited;
end;
end.
Пример использования, процедура AddByte - для помещения очередного принятого байта с COM порта:
procedure TForm1.Button1Click(Sender: TObject);
var
DC : TDataChannel;
i : integer;
begin
DC := TDataChannel.Create( nil );
for i := 0 to 10000 do
DC.AddByte( $A);
DC.AddByte( protoPACKETSTART );
DC.AddByte( $A);
DC.AddByte( protoPACKETSTOP );
DC.AddByte( protoPACKETSTOP );
DC.AddByte( $A);
DC.AddByte( protoPACKETSTOP );
DC.AddByte( $A);
DC.Free;
end;
Kolan (2006-02-09 11:15:00) [10]Поток 1 (транспортный) работает с портом :
- по событию приема принимает из порта данные (сколько бы их ни было принято - хоть один хоть косой десяток), убирает если нужно упр.символы, входит в крит.секцию, записывает принятое в стрим (св-во Position увеличивается на размер записанных данных), устанавливает event, выходит из крит.секции
Поток 2 (обрабатывающий) в цикле с проверкой на Terninated:
Смотря что пишешь в стрим.
Данные из порта (массив байт)
Да и о конкретном протоколе в этой ветке
Протокол такой
Начало - это StartByte и следующий любой не старт.
Конец - это EndByte и следующий любой не EndByte.
В
Kolan © (07.02.06 16:46) [41]
procedure TPackageExtractThread.Execute;
Тут и происходит разбор...
Digitman (2006-02-09 11:07:00) [11]Смотря что пишешь в стрим.
Да и о конкретном протоколе в этой ветке ты ни словом не обмолвился.
Kolan (2006-02-09 10:58:00) [12]Вот я зашел в КС и хочу анализировать. Я просматриваю состояние, пусть они сейчас
sWaitForStart
Раньше я проверял тек эл кольцевого буфера на равенствоStartByte
Вот пример:
case FState of
sWaitForStart:
begin
if (FBuffer[FReadIndex] = StartByte) then
Непойму ка это будет выглядеть в случае стрима?
Digitman (2006-02-09 10:50:00) [13]
> Непонял как анализировать
Тебе видней. Протокол мне неизвестен.
> что делать если его нет
Ничего. Просто спать ..
> Или надо запоминать тек позицию?
Разве в этом проблема?
Kolan (2006-02-09 10:46:00) [14]3. анализирует имеющиеся на сей момент в стриме данные на предмет наличия хотя бы одного целостного пакета, если такового нет, то сбрасывает event и идет на 7.
Непонял как анализировать. И что делать если его нет. Получается что анализировать стрим надо каждый раз зананово.
Или надо запоминать тек позицию?....
Digitman (2006-02-09 10:23:00) [15]
> если данные не пришли то гл поток должен повиснуть?
"Вис" любого потока "лечится" использованием асинхронного режима ввода/вывода.
Kolan (2006-02-09 10:19:00) [16]Германн © (09.02.06 02:35) [73]
А шо если данные не пришли то гл поток должен повиснуть?
Германн (2006-02-09 02:35:00) [17]Очередное моё ФИ насчёт применения доп-потоков для чтения информации с ком-порта. Да, забыл добавить - для "циклического" чтения информации с кои-порта. Ззз, как говаривала ...
Defunct (2006-02-08 23:05:00) [18]упс, забыл поставить закрывающий тэг..
Defunct (2006-02-08 23:02:00) [19]
> Kolan © (08.02.06 11:39) [56]
> 1. Ждать активности COM порта.
> 2. Считать байт, если не управляющий символ - то записать
> в буфер и сместить индекс.
> 3. Если символ "старта" - запонить позицию старта пакета.
>
> 4. Если символ "стопа" - (для начала можно расчитать CRC)
> начиная с запомненной позиции старта скопировать данные
> по текущую позицию и положить в очередь принятых пакетов,
> оповестить транспортный уровень о том, что был получен
> очередной пакет очередной пакет.
> 5. Goto 1.
>
> 2. Чтение по 1 байту критично ка я понял?
>
Да - критично.
> Итак у меня 3 потока
>
> 1. Тот что читает из порта. Он вызовет событие при получении
> 1 байта.
> Тут ничего не меняю
Не надо никакого события вызывать при приеме байта. Событие надо вызывать только тогда, когда пакет целиком выделен.
> 2. По возникновении этого события, основной поток этот байт
> кладет в кольцевой буффер.
> И устанавливает Event.
Как следствие - основной поток даже не знает о наличии кольцевого буфера.
> 3. В свою очередь поток, выделяющий пакеты, просыпается
> по Event и выполняет проверку(она у меня есть, тут тоже
> не меняю ничего?)
Поток который принимает - он же и пакеты выделяет. Т.е. не надо разделять задачу приема байт с выделением пакета на две задачи.
> 4. Прочитав байт он сравнивает индексы(они равны) и сбрасывает
> Event.
Как следствие вышесказанного никто кроме принимающего потока даже и не знает о наличии кольцевого буфера и об индексах.
> Больше всего меня беспокоет то, что потоки как бы общаются
> через главный,
> вызавая соотв. события с Synchronize. Может на прямую можно.
Зачем там Synchronize, зачем 3 потока?
зззз. мне проще написать пример программы чем объяснить вам как должно работать.
Еще раз внимательно прочитайте [54].
> Digitman
Почему Вы предлагаете совместить канальный уровень с транспортным?
реализация со Stream/Queue хороша для транспорта, там где данные уже лежат в виде пакетов. Для канального же уровня (где ведется сборка пакетов) Stream добавит лишь дополнительную проблему - по его очистке.
Eraser (2006-02-08 18:02:00) [20]
> Digitman © (08.02.06 17:47) [69]
ага.. понятно.
Однако тут почти всё зависит от того какая скорость "распарсивания" и какая скорость "считывания"... надо чтобы автор прояснил этот момент.
Если скорость распарсивания намноговыше чем скорость чтения (а я подозреваю, что оно так и есть), то тут вопрос - стоит ли вообще плодить кучу потоков? не проще чтение/распарсивание сделать в одном - последовательно. Т.к. большую часть времени распарсевающий поток будут ждать или проверять "не готов ли буффер/стрим?"