Задача синхронизации встает при одновременном доступе нескольких процессов (или нескольких потоков одного процесса) к какому-либо ресурсу. Поскольку поток в Win32 может быть остановлен в любой, заранее ему неизвестный момент времени возможна ситуация, когда один из потоков не успел завершить модификацию ресурса (например, отображенной на файл области памяти), но был остановлен, а другой поток попытался обратиться к этому же ресурсу. В этот момент ресурс находится в несогласованном состоянии, и последствия обращения к нему могут быть самыми неожиданными – от порчи данных, до нарушения защиты памяти.
Главной идеей, положенной в основу синхронизации потоков в Win32 является использование объектов синхронизации и функций ожидания. Объекты могут находиться в одном из двух состояний – Signaled или Not Signaled. Функции ожидания блокируют выполнение потока до тех пор, пока заданный объект находится в состоянии Not Signaled. Таким образом, поток, которому необходим эксклюзивный доступ к ресурсу, должен выставить какой-либо объект синхронизации в несигнальное состояние, а по окончании – сбросить его в сигнальное. Остальные потоки должны перед доступом к этому ресурсу вызвать функцию ожидания, которая позволит им дождаться освобождения ресурса.
Рассмотрим, какие объекты и функции синхронизации предоставляет нам Win32 API.
Функции синхронизации
Функции синхронизации делятся на две основные категории – это функции, ожидающие единственного объекта и функции, ожидающие одного из нескольких объектов
Функции, ожидающие единственного объекта
Простейшей функцией ожидания является
function WaitForSingleObject(
hHandle: THandle; // идентификатор объекта
dwMilliseconds: DWORD // период ожидания
): DWORD; stdcall;
Функция ожидает перехода объекта hHandle в сигнальное состояние в течении dwMilliseconds миллисекунд. Если в качестве параметра dwMilliseconds передать значение INFINITE, функция будет ждать в течение неограниченного времени. Если dwMilliseconds равен 0, то функция проверяет состояние объекта и немедленно возвращает управление.
Функция возвращает одно из следующих значений:
WAIT_ABANDONED Поток, владевший объектом, завершился, не переведя объект в сигнальное состояние.
WAIT_OBJECT_0 Объект перешел в сигнальное состояние
WAIT_TIMEOUT Истек срок ожидания. Обычно в этом случае генерируется ошибка, либо функция вызывается в цикле до получения другого результата
WAIT_FAILED Произошла ошибка, например неверное значение hHandle. Более подробную информацию можно получить, вызвав GetLastError
Следующий фрагмент кода запрещает Action1 до перехода объекта ObjectHandle в сигнальное состояние. Например, таким образом можно дожидаться завершения процесса, предав в качестве ObjectHandle его идентификатор, полученный функцией CreateProcess.
Code: |
var Reason: DWORD; ErrorCode: DWORD;
Action1.Enabled := FALSE; try repeat Application.ProcessMessages; Reason := WailForSingleObject(ObjectHandle, 10); if Reason = WAIT_FAILED then begin ErrorCode := GetLastError; raise Exception.CreateFmt( 'Wait for object failed with error: %d', [ErrorCode]); end; until Reason <> WAIT_TIMEOUT; finally Actionl.Enabled := TRUE; end;
|
В случае, когда требуется одновременно с ожиданием объекта, перевести в сигнальное состояние другой объект может использоваться функция:
function SignalObjectAndWait(
hObjectToSignal: THandle; // объект, который будет переведен в
// сигнальное состояние
hObjectToWaitOn: THandle; // объект, которого ожидает функция
dwMilliseconds: DWORD; // период ожидания
bAlertable: BOOL // задает, должна ли функция возвращать
// управление в случае запроса на
// завершение операции ввода-вывода
): DWORD; stdcall;
Возвращаемые значения аналогичны функции WaitForSingleObject.
! | В модуле Windows.pas эта функция ошибочно объявлена, как возвращающая значение BOOL. Если Вы намерены её использовать – объявите её корректно или используйте приведение типа возвращенного значения к DWORD |
Объект hObjectToSignal может быть семафором, событием (event), либо мутексом. Параметр bAlertable определяет, будет ли прерываться ожидание объекта, в случае, если операционная система запросит у потока окончание операции асинхронного ввода-вывода, либо асинхронный вызов процедуры. Более подробно это обсуждается ниже.
- Назад
- Вперёд >>
Просьба писать ваши замечания, наблюдения и все остальное,
что поможет улучшить предоставляемую информацию на этом сайте.
ВСЕ КОММЕНТАРИИ МОДЕРИРУЮТСЯ ВРУЧНУЮ, ТАК ЧТО СПАМИТЬ БЕСПОЛЕЗНО!