Читать «Применение 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() {