Суббота, 18.05.2024, 10:48
Приветствую Вас Guest Member

Windows XP / 7 .

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

TGalaGuard = function: Boolean of object;

Процедура-обработчик соответствует входу entry для оператора accept, а охраняющая функция - телу оператору when (язык Ада [7]). Обработчик вызывается всегда в режиме взаимного исключения и только в том случае, когда оба взаимодействующих процесса готовы к рандеву и охраняющая функция возвращает True. Отметим, что если охраняющая функция не задана, то это эквивалентно функции, которая всегда возвращает True, то есть вход всегда разрешен.

Метод Send является входом канала. Процесс, инициирующий рандеву, вызывает именно этот метод для передачи в канал сообщения. Метод Send принимает 2 аргумента: ссылку на процесс-отправитель и указатель на бестиповые данные. Если данные не заданы, то используется ссылка на процесс-оправитель. Третий, необязательный, аргумент - таймаута, время, в течение которого клиентский процесс готов ждать рандеву.


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

Code
TStack = class(TGalaProcess)
private
   FData: array[0..MAX_STACK] of Integer;
   SP:    Integer; // указатель стека

   procedure DoPush(d: Pointer);
   procedure DoPop(d: Pointer);
   function  CanPush: Boolean;
   function  CanPop: Boolean;

protected
   procedure Execute; override;

public
   Push, Pop: TGalaProcessChannel;

   constructor Create(aGroup: Integer);
end;

var
   Stack: TStack;

// Реализация

constructor TStack.Create(aGroup: Integer);
begin
   inherited Create(aGroup);
   // Создаем каналы
   Push := CreateChannel(DoPush, CanPush);
   Pop  := CreateChannel(DoPop,  CanPop);
   SP   := 0; // Инициализируем указатель стека
end;

procedure TStack.Execute;
begin
   // Пока процесс не завершается принудительно, выполняем
   // альтернативный прием по каналам Push и Pop
   while not Terminated do
     AlternativeAccept([Push, Pop]);
end;

procedure TStack.DoPush(d: Pointer);
begin
   // Ложим значение в стек
   FData[SP] := PInteger(d)^;
   Inc(SP);
end;

procedure TStack.DoPop(d: Pointer);
begin
   // Извлекаем значение из стека
   Dec(SP);
   PInteger(d)^ := FData[SP];
end;

function TStack.CanPush: Boolean;
begin
   // Разрешаем, если стек не полон
   result := SP < MAX_STACK;
end;

function TStack.CanPop: Boolean;
begin
   // Разрешаем, если стек не пуст
   result := SP <> 0;
end;

// фрагмент кода процесса-клиента для работы со стеком:
    var
      i: Integer;
    Stack.Push.Send(self, @i);
    Stack.Pop.Send(self, @i);


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

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

Эта группа примитивов инкапсулирует средства синхронизации, предоставляемые операционной системой Windows. Все объекты-сигналы порождаются от базового класса TGalaSignal:

Code
TGalaSignal = class
protected
   FHandle: THandle;

   procedure AfterWaiting(p: TGalaProcess); virtual;

public
   constructor Create(aHandle: THandle);

   procedure Wait(aProcess: TGalaProcess;
             aTimeout: Cardinal = INFINITE);
   property  Handle: THandle read FHandle;
end;


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

Code
TGalaEvent = class(TGalaSignal)
public
   constructor Create(aManualReset: Boolean;
                      aInitialState: Boolean = False;
                      aName: PChar = nil);
   procedure SetState(aState: Boolean); virtual;
   procedure Pulse; virtual;
end;

Конструктор ГалаСобытия имеет 3 аргумента: режим сброса (ManualReset), начальное состояние и необязательное имя. Если ManualReset = False, то событие автоматически становится несигнализирующим после вызова ожидающим процессом метода Wait. Если ManualReset = True, то событие остается сигнализирующим и его нужно явно сбрасывать вызовом SetState(False). Имя события имеет смысл только при взаимодействии нескольких Windows-программ, это относится также к ГалаМьютексам и ГалаСемафорам. Метод Pulse позволяет установить событие и потом сразу сбросить.

Code
TGalaMutex = class(TGalaSignal)
public
   constructor Create(aOwned: Boolean; aName: PChar = nil);
   procedure Release; virtual;
end;


Админ
 
MafiozikOДата: Суббота, 22.08.2009, 23:25 | Сообщение # 21
~Web master~
Группа: Gold пользователь
Зарегистрирован: 10.04.2009
Откуда: Kharkiv
Пол: Мужчина
Сообщений: 366
Статус: Вне сайта
ГалаМьютекс инкапсулируют понятие одиночного ресурса, которым может владеть в один момент времени только один процесс. Слово "Mutex" происходит из соединения двух слов - "Mutual" и "Exclusive", что означает взаимно-исключающее. При создании мьютекса можно сразу завладеть ресурсом, если аргумент aOwned равен True. Для захвата ресурса процесс вызывает метод Wait, для освобождения ресурса - метод Release. Возможен вложенный захват ресурса, то есть, процесс захвативший мьютекс, может захватить его еще раз, но сколько раз захвачен мьютекс, столько раз его нужно освободить.

Code
TGalaSemaphore = class(TGalaSignal)
public
   constructor Create(aMaxCount: Integer;
               aInitialCount: Integer = -1;
               aName: PChar = nil);
   procedure Release(aCount: Integer = 1); virtual;
end;

ГалаСемафор похож на ГалаМьютекс, но, в отличие от мьютекса, инкапсулируют понятие множественного, а не одиночного, ресурса. При создании семафора задается количество единиц разделяемого ресурса (aMaxCount). При создании можно также захватить одну или больше единиц ресурса (aInitialCount), если аргумент не задан, то все ресурсы свободны. Для захвата ресурса процесс вызывает метод Wait, для освобождения ресурса - метод Release. За один раз можно освободить одну или несколько единиц ресурса, но захватить можно только одну за один раз. Пример использования семафора - торговый прилавок с тремя продавцами. Одновременно может быть обслужено не более 3х клиентов: остальные клиенты должны ждать освобождения ресурса - продавца.

Code
TGalaChangeNotification = class(TGalaSignal)
public
   constructor Create(const aDirectory: string;
                      aSubtree: Boolean; aFilter: Cardinal);
   procedure NewDir(const aDirectory: string); virtual;
end;


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

Code
TGalaDeque = class(TGalaSignal)
public
   constructor Create(aDequeSize: Integer = 0);
   function  Count: Integer; virtual;
   procedure PutLast(aObject: TObject); virtual;
   function  GetLast: TObject; virtual;
   procedure PutFirst(aObject: TObject); virtual;
   function  GetFirst: TObject; virtual;
   function  PeekFirst: TObject; virtual;
   function  PeekLast: TObject; virtual;
end;

ГалаДек - это универсальная очередь, которая может быть использована для передачи асинхронных сообщений между процессами, между контейнерами, между процессом и VCL-потоком, процессом и контейнером. Сообщение - это объект любого типа, порождаемого от TObject. Передача сообщения не связана с синхронизацией и ожиданием. Очередь может быть ограниченной или неограниченной длины. Попытка записи в заполненную очередь будет вызывать исключение EGalaOverflow. Когда очередь непуста, то состояние ГалаДека - сигнализирующее, если в очереди нет ни одного сообщения, то состояние ГалаДека - несигнализирующее. Процессы могут ждать поступления сообщений в очередь, используя обычные для всех ГалаСигналов методы. Сообщения могут посылаться либо в начало, либо в конец очереди и извлекаться также либо из начала, либо из конца очереди. Ответственным за создание объекта-сообщения является процесс, посылающий сообщение, а ответственным за использование и уничтожение объекта-сообщения - принимающий процесс. Кроме методов, связанных с изменением состояния очереди, есть два инспектирующих метода (Peek), которые позволяют проконтролировать первый или последний элемент.

Code
TGalaMessage = class(TGalaSignal)
public
   constructor Create;
   destructor  Destroy; override;
   procedure Release; virtual;
   procedure Send(aWnd: THandle; aMessage: Integer); virtual;
   procedure Reply; virtual;
end;


Админ
 
MafiozikOДата: Суббота, 22.08.2009, 23:26 | Сообщение # 23
~Web master~
Группа: Gold пользователь
Зарегистрирован: 10.04.2009
Откуда: Kharkiv
Пол: Мужчина
Сообщений: 366
Статус: Вне сайта
Гала-сообщение - это Гала-сигнал, который можно использовать для передачи данных и команд и последующего ожидания ответа. Он удобен для взаимодействия Гала-процесса с другими объектами, не являющимися Гала-процессами, например VCL-потоком или очередями. Отличительная особенность Гала-сообщения состоит в том, что этот объект осуществляет подсчет ссылок и уничтожается самостоятельно (подобно COM-объектам). Использование Гала-сообщения позволяет послать ответное сообщение даже в том случае, если ожидающий процесс уже уничтожился. Метод Send посылает сообщение окну и увеличивает счетчик ссылок, метод Reply уведомляет о получении Гала-сообщения установкой его в активное состояние (которое сбрасывается при успешном ожидании) и уменьшает счетчик ссылок. Начальное состояние счетчика ссылок равно 1. Принудительное уменьшение счетчика ссылок выполняет метод Release - его вызов означает, что объект больше не нужен. Если счетчик ссылок становится равным нулю, то объект самоуничтожается.

Кроме указанных примитивов в Gala-библиотеке определен служебный класс ГалаЗамок (TGalaLatch), инкапсулирующий понятие критической секции. Он используется внутри многих объектов библиотеки и может быть использован как самостоятельный в тех случаях, когда требуется очень высокая степень эффективности и за это можно заплатить трудоемкостью и сложностью при программировании. Объект имеет два метода: Lock и Unlock. Процесс может заблокировать (закрыть) замок методом Lock - в этом случае все остальные процессы, попытавшиеся вызвать метод Lock будут приостановлены до того момента, когда захвативший процесс не вызовет метод Unlock. При использовании замка нужно быть очень осторожным, так как закрытый замок не дает ожидающим процессам никакого шанса на продолжение. Использование замка практически всегда нужно выполнять в блоке try-finally, например:


Админ
 
MafiozikOДата: Суббота, 22.08.2009, 23:26 | Сообщение # 24
~Web master~
Группа: Gold пользователь
Зарегистрирован: 10.04.2009
Откуда: Kharkiv
Пол: Мужчина
Сообщений: 366
Статус: Вне сайта
Code
var List: TGalaLatch;
. . .  
List.Lock;
try
   // действия со списком
finally
   List.Unlock;
end;


Админ
 
MafiozikOДата: Суббота, 22.08.2009, 23:26 | Сообщение # 25
~Web master~
Группа: Gold пользователь
Зарегистрирован: 10.04.2009
Откуда: Kharkiv
Пол: Мужчина
Сообщений: 366
Статус: Вне сайта
Некоторые объекты VCL имеют встроенную поддержку разделяемого доступа, например: TThreadList, TCanvas.

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

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

Главная форма регистрируется вызовом GalaTheater.NotificationWindow и имеет три метода - обработчика трех стандартных уведомляющих ГалаСообщений:

procedure OnProcessStart(var Mes: TMessage);
message GM_PROCESS_ START;
procedure OnProcessTrace(var Mes: TMessage);
message GM_PROCESS_TRACE;
procedure OnProcessTermination(var Mes: TMessage);
message GM_PROCESS_TERMINATE;


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

Название
Example01: Самый простой - проще не бывает
Действующие лица
Циклический процесс Счетчик
Декорации
Нет
Сценарий
Процесс TCounter каждые 100 миллисекунд передает форме сообщение, содержащее монотонно увеличивающееся число. А форма-декорация его отображает в TLabel. Спектакль начинается с нажатия кнопки Старт и заканчивается нажатием одноименной кнопки Финиш. Ну чем ни таймер?
Цель примера
Показать взаимодействие ГалаПроцессов с VCL-компонентами.

Собственно процесс выглядит следующим образом:

Code
procedure TProcess01.Execute;
var
   Counter: Integer;
begin
   Counter := 0;
   while not Terminated do begin
     Inc(Counter);
     Send(GM_DRAW_01, @Counter);
     Pause(100);
   end;
end;


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

Code
procedure TForm01.OnDraw(var Mes: TMessage); message GM_DRAW_01;
begin
   LabelCounter.Caption := IntToStr(PInteger(Mes.LParam)^);
end;

Метод OnDraw извлекает значение счетчика из Windows-сообщения, преобразует в строку и отображает.

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

Code
procedure TForm01.ButtonStartStopClick(Sender: TObject);
begin
   if Group = 0 then begin
     Group := GalaTheater.GetNewGroup;
     TProcess01.Create(Self, Group);
   end
   else begin
     GalaTheater.DestroyGroup(Group);
     Group := 0;
   end;
end;


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

Название
Example02: Размножающиеся процессы
Действующие лица
Шарики - динамически создаваемые и уничтожаемые процессы
Декорации
Нет
Сценарий
Процессы ведут себя как движущиеся шарики (квадратики), отражающиеся от границ поля. Каждый шарик имеет свой цвет, скорость, время жизни и период размножения (случайные величины). Каждый шарик пытается создать себе подобного, но может размножаться только в том случае, если находится на некотором расстоянии от границы поля и общее число шариков не превышает заданного максимума (который можно динамически изменять).
Цель примера
Показать следующие возможности библиотеки:

1. динамическое создание и уничтожение процессов;
2. защита от перегрузки системы при большом количестве процессов;
3. реакция на нормальное и принудительное завершение;

Жизненный цикл каждого процесса таков (в тексте опускается несущественный для параллельного программирования текст, а опущенные параметры и части кода записываются на псевдокоде):


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

begin
   // шарику даем меньший приоритет, чем VCL-процессу
   Priority := -1;
   // Посылка форме сообщения о создании нового процесса, поскольку
   // именно форма отслеживает общее число процессов
   Send(GM_PROCESS_START);
   while (not Terminated) and не_истекло_время_жизни do begin
     расчет_и_проверка_новых_координат;
     if настало_время_размножения then begin
       расчет_координат_потомка;
       if создание_потомка_возможно then begin
         try
           // Создание потомка
           TProcess02.Create(Group, ParentForm, координаты, направление);
         except
           // Недостаточно системных ресурсов
           on EGalaProcessCreationFail do
             Beep;
         end;
       end;
     end;
     // Отображение шарика на форме
     try
       // Время ожидания рандеву с VCL-потоком ограничено. Если
       // форма перегружена запросами и не может нарисовать шарик
       // за 200 мс, то шарик умирает (от тоски, потому что летать
       // не может). В качестве параметров процесс передает форме
       // ссылку на самого себя
       Send(GM_DRAW_02, Self, ParentForm, 200);
       // Перемещение шарика на новую позицию
       PrevPoint := NextPoint;
       // Пауза для того, чтобы шарики бегали не так быстро
       Pause(Speed);
     except
       // Рандеву с VCL-потоком не состоялось,
       // процесс завершает сам себя (увы, в жизни всяко бывает)
       on EGalaTimeout do
         Terminate;
     end;
   end;
end;


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