FREE Subscription to Dr. Dobb’s Digest: Same Great Content, New Digital Edition
Site Archive (Complete)
C++
Email
Print
Reprint

add to:
Del.icio.us
Digg
Google
Furl
Slashdot
Y! MyWeb
Blink
August 01, 1999

Win32 Multithreading Made Easy

(Page 3 of 4)
August 1999/Win32 Multithreading Made Easy/Figure 3

Figure 3: Classes MultiThreadState and MultiThread

/* ============================================================
MultiThread.h
============================================================ */

#ifndef MULTITHREAD_H #define MULTITHREAD_H

#include <windows.h>

class ThreadableObject;

DWORD WINAPI MultiThreadImpl( LPVOID lpParam );

class MultiThreadState { public: enum { UNINITIALIZED, INITIALIZED, WORKING, SLEEPING, DONE, SUSPENDED, RESUMED };

MultiThreadState(); ~MultiThreadState(); void Reset();

private: // not implemented MultiThreadState( const MultiThreadState& copyMe ); MultiThreadState& operator=( const MultiThreadState& rhs );

friend class MultiThread; friend DWORD WINAPI MultiThreadImpl( LPVOID lpParam );

// Closing handle twice is an error. void CloseThreadHandle(); HANDLE m_hThread;

HANDLE m_hRunEvent; HANDLE m_hWorkEvent; HANDLE m_hDoneEvent;

// Controls access to following data. HANDLE m_hMutex; DWORD m_dwCycleTime; bool m_bStopThread; int m_eState; DWORD m_dwSuspendCount;

ThreadableObject* m_pObject; };

class MultiThread { public: MultiThread(); ~MultiThread();

bool Initialize( ThreadableObject* ptrClass, DWORD dwMilliSecs, DWORD dwStackSize = 0 );

void Run();

void RequestStop(); bool IsStopping() const;

void DoWork();

DWORD CycleTime() const; void CycleTime( DWORD dwCycleTime );

// Similar to Win32 functions, except they return the // threads current suspend count, not the previous count.

DWORD Suspend(); DWORD Resume(); bool IsSuspended( DWORD* dwSuspendCount = NULL ) const;

// Same as Win32 functions GetExitCodeThread and // SetThreadPriority.

BOOL ExitCode( LPDWORD lpExitCode );

BOOL Priority( int nPriority );

// Suspends caller until DoneEvent is signalled.

void WaitUntilDone();

// See enum in MultiThreadState for return values.

int ThreadState() const;

private: // not implemented MultiThread( const MultiThread& copyMe ); MultiThread& operator=( const MultiThread& rhs );

MultiThreadState m_td; }; #endif

/* ============================================== MultiThread.cpp ============================================== */

#include "multithread.h" #include "threadableobject.h" #include "mutexlock.h"

#include <assert.h>

// Error code for SuspendThread, ResumeThread. static const DWORD SR_ERROR = 0xFFFFFFFF;

DWORD WINAPI MultiThreadImpl(LPVOID lpParam) { MultiThreadState* ptrState = (MultiThreadState*) lpParam;

// Synch on the Run Event WaitForSingleObject( ptrState->m_hRunEvent, INFINITE );

bool bStopThread = false; bool bWorkInProgress = true;

DWORD dwCycleTime = 0; DWORD dwReturn = 0; ThreadableObject *pObj = 0;

// Latch values once to start loop { MutexLock( ptrState->m_hMutex ); dwCycleTime = ptrState->m_dwCycleTime; ptrState->m_eState = MultiThreadState::SLEEPING; pObj = ptrState->m_pObject; }

do { // Wait for a Work event, or a timeout. WaitForSingleObject( ptrState->m_hWorkEvent, dwCycleTime );

{ MutexLock( ptrState->m_hMutex ); ptrState->m_eState = MultiThreadState::WORKING; }

bWorkInProgress = pObj->ThreadableTask( &dwReturn );

if ( bWorkInProgress ) { // Latch values for next repitition. MutexLock( ptrState->m_hMutex ); dwCycleTime = ptrState->m_dwCycleTime; bStopThread = ptrState->m_bStopThread; ptrState->m_eState = MultiThreadState::SLEEPING; } } while ( !bStopThread && bWorkInProgress );

// Thread finished. { MutexLock( ptrState->m_hMutex ); ptrState->m_bStopThread = true; ptrState->m_eState = MultiThreadState::DONE; }

SetEvent(ptrState->m_hDoneEvent); return dwReturn; }

MultiThreadState::MultiThreadState() { m_hThread = 0;

// lpEventAttributes, bManualReset, bInitialState, lpName m_hRunEvent = CreateEvent( NULL, false, false, NULL ); assert( m_hRunEvent );

m_hWorkEvent = CreateEvent( NULL, false, false, NULL ); assert( m_hWorkEvent );

// Manual reset since multiple threads can wait on this // event. m_hDoneEvent = CreateEvent( NULL, true, false, NULL ); assert( m_hDoneEvent );

// Security Attr., bInitialOwner, lpName m_hMutex = CreateMutex( NULL, false, NULL ); assert( m_hMutex );

// Should be consistent with code in Reset. m_dwCycleTime = 0; m_bStopThread = false; m_eState = UNINITIALIZED; m_dwSuspendCount = 0; m_pObject = 0; }

MultiThreadState::~MultiThreadState() { CloseThreadHandle();

CloseHandle( m_hRunEvent ); CloseHandle( m_hWorkEvent ); CloseHandle( m_hDoneEvent ); CloseHandle( m_hMutex ); }

void MultiThreadState::Reset() { CloseThreadHandle();

// This code should be consistent with // code in the constructor.

ResetEvent( m_hRunEvent ); ResetEvent( m_hWorkEvent ); ResetEvent( m_hDoneEvent );

m_dwCycleTime = 0; m_bStopThread = false; m_eState = UNINITIALIZED; m_dwSuspendCount = 0; m_pObject = 0; }

void MultiThreadState::CloseThreadHandle() { // Closing a HANDLE twice is an error. // Allowing multiple calls to Initialize // requires this. if ( m_hThread != 0 ) { CloseHandle( m_hThread ); m_hThread = 0; } }

MultiThread::MultiThread() :m_td( MultiThreadState() ) {}

MultiThread::~MultiThread() { // Do what we can to end thread, // but ThreadableTask must still cooperate!

if ( m_td.m_hThread != 0 ) { while ( IsSuspended() ) { Resume(); }

Run(); DoWork();

RequestStop(); WaitUntilDone(); } }

bool MultiThread::Initialize ( ThreadableObject* ptrClass, DWORD dwMilliSecs, DWORD dwStackSize ) { MutexLock( m_td.m_hMutex );

// User must cleanly exit previous thread, if any. assert( m_td.m_eState == MultiThreadState::DONE || m_td.m_eState == MultiThreadState::UNINITIALIZED ); bool bRetVal = false;

// Initialize can be called multiple times. m_td.Reset();

if ( m_td.m_hThread == 0 ) { DWORD dwThreadId = 0; m_td.m_hThread = CreateThread( NULL, dwStackSize, &MultiThreadImpl, (LPVOID) &m_td, 0, &dwThreadId); if ( m_td.m_hThread ) { m_td.m_dwCycleTime = dwMilliSecs; m_td.m_eState = MultiThreadState::INITIALIZED; m_td.m_pObject = ptrClass; bRetVal = true; } else { // Explicitly set just in case. m_td.m_hThread = 0; } } return bRetVal; }

void MultiThread::Run() { MutexLock( m_td.m_hMutex ); if ( m_td.m_eState == MultiThreadState::INITIALIZED ) { SetEvent( m_td.m_hRunEvent ); } }

void MultiThread::RequestStop() { MutexLock( m_td.m_hMutex ); m_td.m_bStopThread = true; }

bool MultiThread::IsStopping() const { MutexLock( m_td.m_hMutex ); return m_td.m_bStopThread; }

void MultiThread::DoWork() { MutexLock( m_td.m_hMutex ); if ( m_td.m_eState == MultiThreadState::SLEEPING ) { SetEvent( m_td.m_hWorkEvent ); } }

DWORD MultiThread::CycleTime() const { MutexLock( m_td.m_hMutex ); return m_td.m_dwCycleTime; }

void MultiThread::CycleTime( DWORD dwCycleTime ) { MutexLock( m_td.m_hMutex ); m_td.m_dwCycleTime = dwCycleTime; }

DWORD MultiThread::Suspend() { MutexLock( m_td.m_hMutex ); if ( ::SuspendThread( m_td.m_hThread ) != SR_ERROR ) { ++m_td.m_dwSuspendCount; if ( m_td.m_dwSuspendCount > 0 ) { m_td.m_eState = MultiThreadState::SUSPENDED; } } return m_td.m_dwSuspendCount; }

DWORD MultiThread::Resume() { MutexLock( m_td.m_hMutex ); if ( ::ResumeThread( m_td.m_hThread ) != SR_ERROR ) { --m_td.m_dwSuspendCount; if ( m_td.m_dwSuspendCount == 0 ) { m_td.m_eState = MultiThreadState::RESUMED; } } return m_td.m_dwSuspendCount; }

bool MultiThread::IsSuspended( DWORD* dwSuspendCount ) const { MutexLock( m_td.m_hMutex ); if ( dwSuspendCount != NULL ) { *dwSuspendCount = m_td.m_dwSuspendCount; } return ( m_td.m_dwSuspendCount != 0 ? true : false ); }

BOOL MultiThread::ExitCode( LPDWORD lpExitCode ) { return ::GetExitCodeThread(m_td.m_hThread, lpExitCode); }

BOOL MultiThread::Priority( int nPriority ) { return ::SetThreadPriority( m_td.m_hThread, nPriority ); }

void MultiThread::WaitUntilDone() { WaitForSingleObject( m_td.m_hDoneEvent, INFINITE ); }

int MultiThread::ThreadState() const { MutexLock( m_td.m_hMutex ); return m_td.m_eState; }

Previous Page | 1 | 2 | 3 | 4 Next Page
RELATED ARTICLES
No Related Articles
TOP 5 ARTICLES
No Top Articles.



MICROSITES
FEATURED TOPIC

ADDITIONAL TOPICS

INFO-LINK