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%


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]

ага.. понятно.
Однако тут почти всё зависит от того какая скорость "распарсивания" и какая скорость "считывания"... надо чтобы автор прояснил этот момент.

Если скорость распарсивания намноговыше чем скорость чтения (а я подозреваю, что оно так и есть), то тут вопрос - стоит ли вообще плодить кучу потоков? не проще чтение/распарсивание сделать в одном - последовательно. Т.к. большую часть времени распарсевающий поток будут ждать или проверять "не готов ли буффер/стрим?"


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

Наверх

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