Активный Объект сформирован как каркас по имени 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() {
> 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();