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

А. И. Легалов

Активный Объект сформирован как каркас по имени ActiveObject. Построение производного класса, как предполагается, обеспечивает реализацию для чистых виртуальных методов InitThread, Run и Flush (также как и написание деструктора).

class ActiveObject {

public:

 ActiveObject();

 virtual ~ActiveObject() {}

 void Kill();

protected:

 virtual void InitThread() = 0;

 virtual void Run() = 0; virtual void FlushThread() = 0;

 static DWORD WINAPI ThreadEntry(void *pArg);

 int _isDying;

 Thread _thread;

};

Конструктор класса ActiveObject инициализирует удерживаемый поток, передавая ему указатель функции, которую предполагается выполнить и указатель "this" на себя. Мы должны отключить предупреждение, сигнализирующее об использовании "this" до полного создания объекта. Мы знаем, что этот объект не будет использоваться раньше положенного, потому что поток создается в неактивном состоянии. Предполагается, сто конструктор производного класса вызывает _thread.Resume() чтобы активизировать поток.

// The constructor of the derived class

// should call

// _thread.Resume ();

// at the end of construction

ActiveObject::ActiveObject() : _isDying (0),

#pragma warning(disable: 4355) // 'this' used before initialized

 _thread(ThreadEntry, this)

#pragma warning(default: 4355)

{ }

Метод Kill вызывает виртуальный метод FlushThread — это необходимо для завершения потока из любого состояния ожидания и дает ему возможность запустить _isDying для проверки флажка.

void ActiveObject::Kill() {

 _isDying++;

 FlushThread();

 // Let's make sure it's gone

 _thread.WaitForDeath();

}

Мы также имеем каркас для функции ThreadEntry (это — статический метод класса ActiveObject, поэтому мы можем определять соглашение о вызовах, требуемое API). Эта функция выполняется удерживаемым потоком. Параметр, получаемый потоком от системы является тем, который мы передали конструктору объекта потока — это указатель "this" Активного Объекта. API ожидает void-указатель, поэтому мы должны делать явное приведение указателя на ActiveObject. Как только мы овладеваем Активным Объектом, мы вызываем его чистый виртуальный метод InitThread, делать все специфические для реализации приготовления, а затем вызываем основной рабочий метод Run. Реализация метода Run оставлена клиенту каркаса.

DWORD WINAPI ActiveObject::ThreadEntry(void* pArg) {

 ActiveObject* pActive = (ActiveObject*)pArg;

 pActive->InitThread();

 pActive->Run();

 return 0;

}

Объект Thread — это тонкая инкапсуляция API. Обратите внимание на флажок CREATE_SUSPENDED, который гарантирует, что нить не начнет выполняться прежде, чем мы не закончим конструирование объекта ActiveObject.

class Thread {

public:

 Thread(DWORD(WINAPI* pFun)(void* arg), void* pArg) {

  _handle = CreateThread(

   0, // Security attributes

   0, // Stack size

   pFun, pArg, CREATE_SUSPENDED, &_tid);

 }

 ~Thread() {

  CloseHandle(_handle);

 }

 void Resume() {

  ResumeThread(_handle);

 }

 void WaitForDeath() {