Common Intermediate Language и системное программирование в Microsoft.Net. Макаров А.В - 126 стр.

UptoLike

int main( void )
{
HANDLE hEvent;
hEvent = CreateEvent( DEFAULT_SECURITY, TRUE, FALSE, NULL );
QueueUserAPC(ApcProc, GetCurrentThread(), (ULONG_PTR)hEvent);
WaitForSingleObject(hEvent,100);
/* код завершения WAIT_TIMEOUT */
SleepEx( 100, TRUE );
/* APC процедура освобождает событие */
WaitForSingleObject(hEvent,100);
/* код завершения WAIT_OBJECT_0 */
WaitForSingleObject(hEvent,100);
/* код завершения WAIT_OBJECT_0 */
CloseHandle( hEvent );
return 0;
}
В примере создается событие с ручным сбросом в занятом состоянии.
При первом вызове функции WaitForSingleObject событие все еще занято,
поэтому выход из функции осуществляется по таймауту. При втором вызо-
ве уже успевает сработать APC и событие свободно – поэтому функция
ожидания завершится с успехом. К третьему вызову состояние события
не меняется, поэтому результат аналогичный.
Если в приведенном примере изменить событие с ручным сбросом на
событие с автоматическим сбросом (второй параметр функции CreateEvent
должен быть FALSE), то при втором обращении к WaitForSingleObject функ-
ция завершится также с кодом WAIT_OBJECT_0, но при этом событие автома-
тически будет переведено в занятое состояние. В результате третий вызов
функции WaitForSingleObject завершится по таймауту.
Поведение событий с ручным и автоматическим сбросом особенно
различаются в случае, если несколько потоков ждут одного события: для
события с ручным сбросом, при установке его в свободное состояние, вы-
полнение могут продолжить все ожидающие потоки; а для события с авто-
матическим сбросом – только один, так как событие будет сразу переведе-
но в занятое состояние.
В некоторых случаях бывает надо перевести событие в свободное со-
стояние, чтобы ожидающие на данный момент времени потоки могли
продолжить свое выполнение, после чего снова вернуть в занятое. Вместо
пары вызовов SetEvent...ResetEvent, во время выполнения которых пла-
нировщик вполне может переключиться на другие потоки (в итоге время
нахождения события в свободном состоянии непредсказуемо), целесооб-
разно использовать функцию PulseEvent, которая как бы выполняет сброс
и установку события, но в рамках одной операции.
Разработка параллельных приложений для ОС Windows
239
ны специальные функции, так что потоки могут явным образом управлять
состоянием таких объектов, обеспечивая взаимную синхронизацию. Эти
объекты являются базовыми примитивами, на которых часто строятся бо-
лее сложные синхронизирующие объекты.
При проектировании составных объектов иногда возникает задача
изменения состояния одного из примитивных объектов при переходе к
ожиданию другого. Если такие операции выполнять поочередно, то меж-
ду вызовами функции, изменяющей состояние объекта, и функции ожи-
дания возможно срабатывание планировщика и переключение потоков;
то есть время, проходящее между изменением состояния одного объекта и
началом ожидания другого, оказывается непредсказуемым. Чтобы избе-
жать такой ситуации, предусмотрена функция SignalObjectAndWait, пере-
водящая один объект в свободное состояние и ожидающая другой.
Стандартные синхронизирующие объекты могут быть именованны-
ми (функции, создающие эти объекты, имеют параметр, указывающий их
имя), а могут быть «безымянными», если вместо имени указать NULL. По-
пытка создания именованных объектов с совпадающими именами приве-
дет или к получению нового описателя существующего объекта (если ти-
пы существующего объекта и вновь создаваемого одинаковы), или к
ошибке (если типы разные). Именованные объекты обычно используют
для межпроцессного взаимодействия, а безымянные – для взаимодейст-
вия потоков в одном процессе.
События
Обычно событие – некоторый объект, который может находиться в
одном из двух состояний: занятом или свободном. Переключение состоя-
ний осуществляется явным вызовом соответствующих функций; при этом
любой процесс/поток, имеющий необходимые права доступа к объекту
«событие», может изменить его состояние.
В Windows различают события с ручным и с автоматическим сбросом
(тип и начальное состояние задаются при создании события функцией
CreateEvent). События с ручным сбросом ведут себя обычным образом:
функция SetEvent переводит событие в свободное (сигнальное) состояние,
а функция ResetEvent – в занятое (не сигнальное). События с автоматиче-
ским сбросом переводятся в занятое состояние либо явным вызовом
функции ResetEvent, либо ожидающей функцией WaitFor....
#define DEFAULT_SECURITY (LPSECURITY_ATTRIBUTES)NULL
VOID CALLBACK ApcProc( ULONG_PTR dwData )
{
SetEvent( (HANDLE)dwData );
}
238
CIL и системное программирование в Microsoft .NET
238                          CIL и системное программирование в Microsoft .NET   Разработка параллельных приложений для ОС Windows                   239


ны специальные функции, так что потоки могут явным образом управлять                  int main( void )
состоянием таких объектов, обеспечивая взаимную синхронизацию. Эти                    {
объекты являются базовыми примитивами, на которых часто строятся бо-                    HANDLE hEvent;
лее сложные синхронизирующие объекты.                                                   hEvent = CreateEvent( DEFAULT_SECURITY, TRUE, FALSE, NULL );
     При проектировании составных объектов иногда возникает задача                      QueueUserAPC(ApcProc, GetCurrentThread(), (ULONG_PTR)hEvent);
изменения состояния одного из примитивных объектов при переходе к                       WaitForSingleObject(hEvent,100);
ожиданию другого. Если такие операции выполнять поочередно, то меж-                       /* код завершения WAIT_TIMEOUT */
ду вызовами функции, изменяющей состояние объекта, и функции ожи-                       SleepEx( 100, TRUE );
дания возможно срабатывание планировщика и переключение потоков;                          /* APC процедура освобождает событие */
то есть время, проходящее между изменением состояния одного объекта и                   WaitForSingleObject(hEvent,100);
началом ожидания другого, оказывается непредсказуемым. Чтобы избе-                        /* код завершения WAIT_OBJECT_0 */
жать такой ситуации, предусмотрена функция SignalObjectAndWait, пере-                   WaitForSingleObject(hEvent,100);
водящая один объект в свободное состояние и ожидающая другой.                             /* код завершения WAIT_OBJECT_0 */
     Стандартные синхронизирующие объекты могут быть именованны-                        CloseHandle( hEvent );
ми (функции, создающие эти объекты, имеют параметр, указывающий их                      return 0;
имя), а могут быть «безымянными», если вместо имени указать NULL. По-                 }
пытка создания именованных объектов с совпадающими именами приве-                     В примере создается событие с ручным сбросом в занятом состоянии.
дет или к получению нового описателя существующего объекта (если ти-             При первом вызове функции WaitForSingleObject событие все еще занято,
пы существующего объекта и вновь создаваемого одинаковы), или к                  поэтому выход из функции осуществляется по таймауту. При втором вызо-
ошибке (если типы разные). Именованные объекты обычно используют                 ве уже успевает сработать APC и событие свободно – поэтому функция
для межпроцессного взаимодействия, а безымянные – для взаимодейст-               ожидания завершится с успехом. К третьему вызову состояние события
вия потоков в одном процессе.                                                    не меняется, поэтому результат аналогичный.
     События                                                                          Если в приведенном примере изменить событие с ручным сбросом на
     Обычно событие – некоторый объект, который может находиться в               событие с автоматическим сбросом (второй параметр функции CreateEvent
одном из двух состояний: занятом или свободном. Переключение состоя-             должен быть FALSE), то при втором обращении к WaitForSingleObject функ-
ний осуществляется явным вызовом соответствующих функций; при этом               ция завершится также с кодом WAIT_OBJECT_0, но при этом событие автома-
любой процесс/поток, имеющий необходимые права доступа к объекту                 тически будет переведено в занятое состояние. В результате третий вызов
«событие», может изменить его состояние.                                         функции WaitForSingleObject завершится по таймауту.
     В Windows различают события с ручным и с автоматическим сбросом                  Поведение событий с ручным и автоматическим сбросом особенно
(тип и начальное состояние задаются при создании события функцией                различаются в случае, если несколько потоков ждут одного события: для
CreateEvent). События с ручным сбросом ведут себя обычным образом:               события с ручным сбросом, при установке его в свободное состояние, вы-
функция SetEvent переводит событие в свободное (сигнальное) состояние,           полнение могут продолжить все ожидающие потоки; а для события с авто-
а функция ResetEvent – в занятое (не сигнальное). События с автоматиче-          матическим сбросом – только один, так как событие будет сразу переведе-
ским сбросом переводятся в занятое состояние либо явным вызовом                  но в занятое состояние.
функции ResetEvent, либо ожидающей функцией WaitFor....                               В некоторых случаях бывает надо перевести событие в свободное со-
                                                                                 стояние, чтобы ожидающие на данный момент времени потоки могли
      #define DEFAULT_SECURITY (LPSECURITY_ATTRIBUTES)NULL                       продолжить свое выполнение, после чего снова вернуть в занятое. Вместо
                                                                                 пары вызовов SetEvent...ResetEvent, во время выполнения которых пла-
      VOID CALLBACK ApcProc( ULONG_PTR dwData )                                  нировщик вполне может переключиться на другие потоки (в итоге время
      {                                                                          нахождения события в свободном состоянии непредсказуемо), целесооб-
        SetEvent( (HANDLE)dwData );                                              разно использовать функцию PulseEvent, которая как бы выполняет сброс
      }                                                                          и установку события, но в рамках одной операции.