Воскресенье, 05.05.2024, 00:48
Приветствую Вас Guest Member

Windows XP / 7 .

[ Новые сообщения · Участники · Правила форума · Поиск · RSS ]
  • Страница 3 из 3
  • «
  • 1
  • 2
  • 3
Архив - только для чтения
Форум <<Помощь по компьютерам>> » Низкоуровневое программирование » Исходные коды » Исходные коды: Delphi (Исходные коды: Delphi)
Исходные коды: Delphi
MafiozikOДата: Суббота, 22.08.2009, 23:28 | Сообщение # 31
~Web master~
Группа: Gold пользователь
Зарегистрирован: 10.04.2009
Откуда: Kharkiv
Пол: Мужчина
Сообщений: 366
Статус: Вне сайта
Действия, совершаемые при нормальном и аварийном завершении в данном случае одинаковы - шарик стирает себя с экрана и уменьшает общее число шариков:

Code
procedure TProcess02.OnPrematureTermination;
begin
    OnNormalTermination;
end;

procedure TProcess02.OnNormalTermination;
begin
    Color := clWhite;
    // Стираем себя
    Send(GM_DRAW_02);
    // Посылаем форме уведомление о своем завершении
    Send(GM_PROCESS_TERMINATE);
end;

Форма отвечает на сообщения процессов тремя процедурами - обработчиками сообщений: GM_PROCESS_START, GM_PROCESS_TERMINATE и GM_DRAW_02:

Code
procedure TForm02.OnStart(var Mes: TMessage);
begin
    Inc(Count);

Code
LabelProcessCount.Caption := IntToStr(Count);
end;

procedure TForm02.OnTermination(var Mes: TMessage);
begin
Dec(Count);
LabelProcessCount.Caption := IntToStr(Count);
end;

procedure TForm02.OnDraw(var Mes: TMessage);
begin
with TProcess02(Mes.LParam) do begin
отрисовка_шарика;
end;
end;


Админ


Сообщение отредактировал MafiozikO - Суббота, 22.08.2009, 23:29
 
MafiozikOДата: Суббота, 22.08.2009, 23:29 | Сообщение # 32
~Web master~
Группа: Gold пользователь
Зарегистрирован: 10.04.2009
Откуда: Kharkiv
Пол: Мужчина
Сообщений: 366
Статус: Вне сайта
Если внимательно наблюдать за поведением шариков, особенно при их большом количестве, то можно заметить следующее - иногда количество шариков превышает заданный максимум. Почему это происходит? Если посмотреть на то, как процесс создается, можно заметить, что сначала процесс-родитель запрашивает у формы - можно ли создавать потомка? Затем процесс создает потомка и уже сам потомок дает форме сообщение о создании, которое увеличивает действительное число процессов. Т. е. между проверкой возможности создания и реальным созданием проходит время, в которое операционная система может перейти к выполнению другого процесса-шарика, который также готов к размножению. То есть, подтверждение на создание потомка могут получить несколько процессов-родителей прежде, чем потомки действительно будут созданы. Я сознательно не стал усложнять алгоритм подтверждения, чтобы продемонстрировать проблемы, которые могут возникнуть в системе с вытесняющей многозадачностью. Корректно эту проблему в данном примере можно было бы решить с помощью счетного семафора TGalaSemaphore или с помощью другого параллельного процесса. Такой процесс регистрировал бы запрос на создание и уменьшал бы значение счетчика - но это потребует также обработки ситуации, в которой процесс-родитель получил подтверждение на создание потомка, но не смог его создать.

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


Админ
 
MafiozikOДата: Суббота, 22.08.2009, 23:29 | Сообщение # 33
~Web master~
Группа: Gold пользователь
Зарегистрирован: 10.04.2009
Откуда: Kharkiv
Пол: Мужчина
Сообщений: 366
Статус: Вне сайта
Спектакль 03

Название
Example03: Буфер между процессами
Примечание
Этот и три последующих примера внешне очень похожи - формы всех примеров наследуются от базовой формы и все процессы этих примеров порождаются от базовых процессов (файлы PMU.pas и PMU.dfm)
Взаимодействующие лица

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

Декорации
Нет
Сценарий
Очень прост - двое производят, третий потребляет, а четвертый работает складом готовой продукции. Интрига сюжета в том, что Буфер имеет ограниченную емкость, а все три процесса могут создаваться независимо друг от друга и фактически ничего не знают друг о друге. Процессы-производители могут передавать свои данные только в том случае, если в буфере есть место, процесс-потребитель может что-то взять из буфера, если он не пуст, в остальных случаях процессы вынуждены ждать.
Цель примера
Показать взаимодействие нескольких асинхронных процессов с помощью разделяемого ресурса - буфера, который и является ключевой фигурой в сюжете.

Рассмотрим буфер подробнее:


Админ
 
MafiozikOДата: Суббота, 22.08.2009, 23:29 | Сообщение # 34
~Web master~
Группа: Gold пользователь
Зарегистрирован: 10.04.2009
Откуда: Kharkiv
Пол: Мужчина
Сообщений: 366
Статус: Вне сайта
Code
TBuffer03 = class(TGalaContainer)
protected
   Buffer: array[TBufferSize03] of Integer;
   Count:  Integer;
   PPut:   TBufferSize03;
   PGet:   TBufferSize03;

   function  CanPut: Boolean;
   procedure DoPut(aData: Pointer);
   function  CanGet: Boolean;
   procedure DoGet(aData: Pointer);

public
   Put: TGalaContainerChannel;
   Get: TGalaContainerChannel;

   constructor Create;
end;


Админ
 
MafiozikOДата: Суббота, 22.08.2009, 23:30 | Сообщение # 35
~Web master~
Группа: Gold пользователь
Зарегистрирован: 10.04.2009
Откуда: Kharkiv
Пол: Мужчина
Сообщений: 366
Статус: Вне сайта
Буфер предоставляет для наружного использования два своих канала - один для записи, другой для чтения. Вся реализация буфера скрыта в приватной области и включает собственно буфер данных, количество записанных данных и индексы записи и чтения. Создаются каналы в конструкторе контейнера, а уничтожаются автоматически при завершении процесса. Сам контейнер создается при создании формы (то есть, существует вечно, в отличие от динамически создаваемых процессов).

Code
constructor TBuffer03.Create;
begin
   inherited Create;
   Count := 0;
   PPut  := Low(TBufferSize03);
   PGet  := Low(TBufferSize03);
   Put   := CreateChannel(DoPut, CanPut);
   Get   := CreateChannel(DoGet, CanGet);
end;

Все действия буфера сосредоточены в процедурах и функциях каналов и достаточно понятны без комментариев, так как реализуется хрестоматийный алгоритм кольцевого буфера:

Code
function TBuffer03.CanPut: Boolean;
begin
   result := Count < MAX_BUFFER_COUNT_03;
end;

procedure TBuffer03.DoPut(aData: Pointer);
begin
   Buffer[PPut] := PInteger(aData)^;
   Inc(PPut);
   if PPut > High(TBufferSize03) then
     PPut := Low(TBufferSize03);
   Inc(Count);
end;

function TBuffer03.CanGet: Boolean;
begin
   result := Count > 0;
end;

procedure TBuffer03.DoGet(aData: Pointer);
begin
   PInteger(aData)^ := Buffer[PGet];
   Inc(PGet);
   if PGet > High(TBufferSize03) then
     PGet := Low(TBufferSize03);
   Dec(Count);
end;


Админ
 
MafiozikOДата: Суббота, 22.08.2009, 23:30 | Сообщение # 36
~Web master~
Группа: Gold пользователь
Зарегистрирован: 10.04.2009
Откуда: Kharkiv
Пол: Мужчина
Сообщений: 366
Статус: Вне сайта
Действия процессов-производителей по взаимодействию с буфером тривиальны - они посылают буферу сообщение в канал, после чего увеличивают свое значение и выполняют случайную задержку. Посылка значения в канал Put выполняется так:

Code
Buffer.Put.Send(Self, @Counter);

Действия потребителя также просты, но мы рассмотрим их подробнее:

Code

procedure TProcessUser03.Execute;
var
   i: Integer;
begin
   while not Terminated do begin
     Trace('Жду');
     Buffer.Get.Send(Self, @i);
     Send(GM_USER_PM, @i);
     Trace('Потребляю');
     Pause(500);
   end;
end;


Админ
 
MafiozikOДата: Суббота, 22.08.2009, 23:31 | Сообщение # 37
~Web master~
Группа: Gold пользователь
Зарегистрирован: 10.04.2009
Откуда: Kharkiv
Пол: Мужчина
Сообщений: 366
Статус: Вне сайта
Для приема данных из буфера, процесс посылает ему сообщение в канал Get, передавая указатель на значение. Для вывода на экран полученных данных, процесс взаимодействует с формой. В этом примере вводится новое понятие - отладочная трассировка, которая выполняется процедурой Trace. Эта процедура выводит указанную строку в список процессов главной формы примеров. Запускайте в разном сочетании процессы и наблюдайте их состояния. Good luck.

Админ
 
Форум <<Помощь по компьютерам>> » Низкоуровневое программирование » Исходные коды » Исходные коды: Delphi (Исходные коды: Delphi)
  • Страница 3 из 3
  • «
  • 1
  • 2
  • 3
Поиск: