Содержание материала

Объекты синхронизации

Объектами синхронизации называются объекты Windows, идентификаторы которых могут использоваться в функциях синхронизации. Они делятся на две группы объекты, использующиеся только для синхронизации и объекты, которые используются в других целях, но могут вызывать срабатывание функций ожидания. К первой группе относятся:

Event (событие)

Позволяет известить один или несколько ожидающих потоков о наступлении события. Event бывает

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

Автоматически отключаемый        Автоматически переключается в несигнальное состояние операционной системой, когда один из ожидающих его потоков завершается.        

Для создания объекта используется функция:

 

function CreateEvent(

lpEventAttributes: PSecurityAttributes;  // Адрес структуры

                                          // TSecurityAttributes

  bManualReset,         // Задает, будет Event переключаемым

                        // вручную (TRUE) или автоматически (FALSE)

  bInitialState: BOOL;  // Задает начальное состояние. Если TRUE -

                        // объект в сигнальном состоянии

  lpName: PChar         // Имя или NIL, если имя не требуется

): THandle; stdcall;     // Возвращает идентификатор созданного

                        // объекта

 

Структура TSecurityAttributes описана, как:

 

TSecurityAttributes = record

nLength: DWORD;                // Размер структуры, должен

                                // инициализироваться как

                                // SizeOf(TSecurityAttributes)

lpSecurityDescriptor: Pointer; // Адрес дескриптора защиты. В

                                // Windows 95 и 98 игнорируется

                                // Обычно можно указывать NIL

bInheritHandle: BOOL;          // Задает, могут ли дочерние

                                // процессы наследовать объект

end;

 

Если не требуется задание особых прав доступа под Windows NT или возможности наследования объекта дочерними процессами, в качестве параметра lpEventAttributes можно передавать NIL. В этом случае объект не может наследоваться дочерними процессами и ему задается дескриптор защиты «по умолчанию».

Параметр lpName позволяет разделять объекты между процессами. Если lpName совпадает с именем уже существующего объекта типа Event, созданного текущим или любым другим процессом, функция не создает нового объекта, а возвращает идентификатор уже существующего. При этом игнорируются параметры bManualReset, bInitialState и lpSecurityDescriptor. Проверить, был объект создан, или используется уже существующий можно следующим образом:

 

hEvent := CreateEvent(NIL, TRUE, FALSE, 'EventName');

if hEvent = 0 then

RaiseLastWin32Error;

if GetLastError = ERROR_ALREADY_EXISTS then begin

// Используем ранее созданный объект

end;

 

Если объект используется для синхронизации внутри одного процесса, его можно объявить как глобальную переменную и создавать без имени.

Имя объекта не должно совпадать с именем любого из существующих объектов типов Semaphore, Mutex, Job, Waitable Timer или FileMapping. В случае совпадения имен, функция возвращает ошибку.

Если известно, что Event уже создан, для получения доступа к нему можно вместо CreateEvent воспользоваться функцией:

 

function OpenEvent(

dwDesiredAccess: DWORD;  // Задает права доступа к объекту

bInheritHandle: BOOL;    // Задает, может ли объект наследоваться

                          // дочерними процессами

lpName: PChar            // Имя объекта

): THandle; stdcall;

 

Функция возвращает идентификатор объекта, либо 0, в случае ошибки. Параметр dwDesiredAccess может принимать одно из следующих значений:

EVENT_ALL_ACCESS        Приложение получает полный доступ к объекту        

EVENT_MODIFY_STATE        Приложение может изменять состояние объекта функциями SetEvent и ResetEvent        

SYNCHRONIZE        Только для Windows NT приложение может использовать объект только в функциях ожидания        

После получения идентификатора можно приступать к его использованию. Для этого имеются следующие функции:

 

function SetEvent(hEvent: THandle): BOOL; stdcall;

 

Устанавливает объект в сигнальное состояние

 

function ResetEvent(hEvent: THandle): BOOL; stdcall;

 

Сбрасывает объект, устанавливая его в несигнальное состояние

 

function PulseEvent(hEvent: THandle): BOOL; stdcall

 

Устанавливает объект в сигнальное состояние, дает отработать всем функциям ожидания, ожидающим этот объект, а затем снова сбрасывает его.

В WinAPI события используются, для выполнения операций асинхронного ввода-вывода. Следующий пример показывает, как приложение инициирует запись одновременно в два файла, а затем ожидает завершения записи перед продолжением работы. Такой подход может обеспечить более высокую производительность при высокой интенсивности ввода-вывода, чем последовательная запись.

Code:

var

Events: array[0..1] of THandle;  // Массив объектов синхронизации

Overlapped: array[0..1] of TOverlapped;

 

...

 

// Создаем объекты синхронизации

Events[0] := CreateEvent(NIL, TRUE, FALSE, NIL);

Events[1] := CreateEvent(NIL, TRUE, FALSE, NIL);

 

// Инициализируем структуры TOverlapped

FillChar(Overlapped, SizeOf(Overlapped), 0);

Overlapped[0].hEvent := Events[0];

Overlapped[1].hEvent := Events[1];

 

// Начинаем асинхронную запись в файлы

WriteFile(hFirstFile, FirstBuffer, SizeOf(FirstBuffer),

FirstFileWritten, @Overlapped[0]);

WriteFile(hSecondFile, SecondBuffer, SizeOf(SecondBuffer),

SecondFileWritten, @Overlapped[1]);

 

// Ожидаем завершения записи в оба файла

WaitForMultipleObjects(2, @Events, TRUE, INFINITE);

 

// Уничтожаем объекты синхронизации

CloseHandle(Events[0]);

CloseHandle(Events[1]);

 

 

По завершении работы с объектом, он должен быть уничтожен функцией CloseHandle.

Delphi предоставляет класс TEvent, инкапсулирующий функциональность объекта Event. Класс расположен в модуле SyncObjs.pas и объявлен следующим образом:

 

Code:

type

TWaitResult = (wrSignaled, wrTimeout, wrAbandoned, wrError);

 

TEvent = class(THandleObject)

public

   constructor Create(EventAttributes: PSecurityAttributes;

     ManualReset, InitialState: Boolean; const Name: string);

   function WaitFor(Timeout: DWORD): TWaitResult;

   procedure SetEvent;

   procedure ResetEvent;

end;

 

 

 

Назначение методов очевидно из их названий. Использование этого класса позволяет не вдаваться в тонкости реализации вызываемых функций Windows API. Для простейших случаев объявлен еще один класс с упрощенным конструктором.

Code:

type

TSimpleEvent = class(TEvent)

public

   constructor Create;

end;

 

 

constructor TSimpleEvent.Create;

begin

FHandle := CreateEvent(nil, True, False, nil);

end;

 

 

 

Добавить комментарий

Не использовать не нормативную лексику.

Просьба писать ваши замечания, наблюдения и все остальное,
что поможет улучшить предоставляемую информацию на этом сайте.

ВСЕ КОММЕНТАРИИ МОДЕРИРУЮТСЯ ВРУЧНУЮ, ТАК ЧТО СПАМИТЬ БЕСПОЛЕЗНО!


Защитный код
Обновить