Читать «Применение Windows API» онлайн - страница 26

А. И. Легалов

  WaitForSingleObject(_handle, 2000);

 }

private:

 HANDLE _handle;

 DWORD _tid; // thread id

};

Синхронизация — это то, что действительно делает многозадачный режим столь интенсивно используемым. Давайте, начнем со взаимных исключений. Класс Mutex — тонкая инкапсуляция API. Вы внедряете Mutexes (мутации) в ваш Активный Объект, а затем используете их через Блокировки. Блокировка (Lock) — умный объект, который создается на стеке. В результате чего, во время обслуживания, ваш объект защищен от любых других потоков. Класс Lock — одно из приложений методологии Управления ресурсами. Вы должны поместить Lock внутри всех методов вашего Активного Объекта, которые разделяют доступ к данным с другими потоками.

class Mutex {

 friend class Lock;

public:

 Mutex() {

  InitializeCriticalSection(&_critSection);

 }

 ~Mutex() {

  DeleteCriticalSection(&_critSection);

 }

private:

 void Acquire() {

  EnterCriticalSection(&_critSection);

 }

 void Release() {

  LeaveCriticalSection(&_critSection);

 }

 CRITICAL_SECTION _critSection;

};

class Lock {

public:

 // Acquire the state of the semaphore

 Lock(Mutex& mutex) : _mutex(mutex) {

  _mutex.Acquire();

 }

 // Release the state of the semaphore

 ~Lock() {

  _mutex.Release();

 }

 private:

  Mutex& _mutex;

};

Событие — это сигнальное устройство, которое потоки используют, чтобы связаться друг с другом. Вы внедряете Событие (Event) в ваш активный объект. Затем Вы переводите удерживаемый поток в состояние ожидания, пока некоторый другой поток не освободит его. Не забудьте однако, что, если ваш удерживаемй поток ожидает события, он не может быть завершен. Именно поэтому Вы должны вызывать Release из метода Flush.

class Event {

public:

 Event() {

  // start in non-signaled state (red light)

  // auto reset after every Wait

  _handle = CreateEvent(0, FALSE, FALSE, 0);

 }

 ~Event() {

  CloseHandle(_handle);

 }

 // put into signaled state

 void Release() {

  SetEvent(_handle);

 }

 void Wait() {

  // Wait until event is in signaled (green) state

  WaitForSingleObject(_handle, INFINITE);

 }

 operator HANDLE() { return _handle; }

private:

 HANDLE _handle;

};

Чтобы увидеть, как эти классы могут быть использованы, я предлагаю небольшую подсказку. Вы можете перейти к странице, которая объясняет, как класс ActiveObject используется в Частотном анализаторе для асинхронной модификации дисплеев. Или, Вы можете изучить более простой пример Наблюдателя Папки, который спокойно ждет, отображая папки, и пробуждается только, когда присходит изменение ее содержимого.

Жаль, что я не могу сказать, что программирование потоков является простым. Однако, оно будет проще, если Вы станете использовать правильные примитивы. Это примитивы, которые я рекламировал: ActiveObject, Thread, Mutex, Lock и Event. Некоторые из них фактически доступны в MFC. К примеру, там есть блокирующий объект CLock (а может быть — это ЧАСЫ [CLock — игра слов]?) деструктор которого управляет, критической секцией (он немного менее удобен из-за «двухшаговой» конструкции: Вы должны создать его, а затем выбирать его в два отдельных шага — как будто бы вы захотели создать его, а затем передумать). Другое отличие: MFC предлагает только некоторую тонкую фанеру над API и ничего нового.