207 lines
5.6 KiB
C++
207 lines
5.6 KiB
C++
//+----------------------------------------------------------------------------
|
|
//
|
|
// Copyright (C) 1997, Microsoft Corporation
|
|
//
|
|
// File: thrdpl2.h
|
|
//
|
|
// Contents: definitions needed for clients of the thrdpool2 lib
|
|
//
|
|
// Description: The thrdpool library defines the CThreadPool base class.
|
|
// Users of this lib should define their own derived class
|
|
// that inherits from CThreadPool. A CThreadPool object
|
|
// has a set of threads that is used to do some work. It also
|
|
// has a common completion port that is used to queue work items.
|
|
// All worker threads will normally block on
|
|
// GetQueuedCompletionStatus(). Clients of the CThreadPool
|
|
// object will call PostWork() to get work done. This will
|
|
// result in one of the worker threads returning from
|
|
// GetQueuedCompletionStatus() and calling the derived class'
|
|
// WorkCompletion() routine with a pvContext.
|
|
//
|
|
// CThreadPool provides the following features:
|
|
// - creation with an initial number of threads
|
|
// - deletion
|
|
// - ability to submit work items
|
|
// - grow pool of threads
|
|
// - shrink pool of threads
|
|
//
|
|
// NOTE: the base class has no knowledge of the type of work
|
|
// getting done. It just manages the details of getting work
|
|
// requests and distributing it to threads in its pool. This
|
|
// allows the derived class to focus on processing the actual
|
|
// work item without bothering about queueing etc.
|
|
//
|
|
// Completion ports are used merely to leverage its queueing
|
|
// semantics and not for I/O. If the work done by each thread
|
|
// is fairly small, LIFO semantics of completion ports will
|
|
// reduce context switches.
|
|
//
|
|
// Functions:
|
|
//
|
|
// History: 09/18/97 Rajeev Rajan (rajeevr) Created
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#ifndef THRDPL2_H
|
|
#define THRDPL2_H
|
|
|
|
//
|
|
// Base thread pool class
|
|
//
|
|
class CThreadPool
|
|
{
|
|
public:
|
|
//
|
|
// Constructor, destructor
|
|
//
|
|
CThreadPool();
|
|
virtual ~CThreadPool();
|
|
|
|
//
|
|
// creates the required number of worker threads and completion port
|
|
//
|
|
BOOL Initialize( DWORD dwConcurrency, DWORD dwMaxThreads, DWORD dwInitThreads );
|
|
|
|
//
|
|
// shutdown the thread pool
|
|
//
|
|
BOOL Terminate( BOOL fFailedInit = FALSE, BOOL fShrinkPool = TRUE );
|
|
|
|
//
|
|
// clients should call this to post work items
|
|
//
|
|
BOOL PostWork(PVOID pvWorkContext);
|
|
|
|
//
|
|
// expose shutdown event
|
|
//
|
|
HANDLE QueryShutdownEvent() { return m_hShutdownEvent; }
|
|
|
|
//
|
|
// A job represents a series of PostWork() items
|
|
//
|
|
VOID BeginJob( PVOID pvContext );
|
|
|
|
//
|
|
// Wait for job to complete ie all PostWork() items are done
|
|
//
|
|
DWORD WaitForJob( DWORD dwTimeout );
|
|
|
|
//
|
|
// Job context is used to process all work items in a job
|
|
//
|
|
PVOID QueryJobContext() { return m_pvContext; }
|
|
|
|
//
|
|
// shrink pool by dwNumThreads
|
|
//
|
|
BOOL ShrinkPool( DWORD dwNumThreads );
|
|
|
|
//
|
|
// grow pool by dwNumThreads
|
|
//
|
|
BOOL GrowPool( DWORD dwNumThreads );
|
|
|
|
//
|
|
// Shrink all the existing threads
|
|
//
|
|
VOID ShrinkAll();
|
|
|
|
protected:
|
|
|
|
//
|
|
// derived method called when work items are posted
|
|
//
|
|
virtual VOID WorkCompletion(PVOID pvWorkContext) = 0;
|
|
|
|
//
|
|
// For those who has knowledge about automatic shutdown of the thread
|
|
// pool, this function is used as an interface for implementing
|
|
// shutting down the thread pool for itself. The function is called
|
|
// when the last thread in the pool goes away because of shutdown
|
|
// event has been fired.
|
|
//
|
|
// The reason for this interface is: in some scenarios the shutting
|
|
// down thread is from the same thread pool and it will cause deadlock.
|
|
// Users of thread pool who expects this will happen should not call
|
|
// WaitForJob, and should call Terminate and delete in this call back.
|
|
//
|
|
virtual VOID AutoShutdown() {
|
|
//
|
|
// People who doesn't care about this function does a no-op
|
|
//
|
|
};
|
|
|
|
private:
|
|
|
|
friend DWORD __stdcall ThreadDispatcher(PVOID pvWorkerThread);
|
|
|
|
//
|
|
// check for matching Init(), Term() calls
|
|
//
|
|
LONG m_lInitCount;
|
|
|
|
//
|
|
// handle to completion port
|
|
//
|
|
HANDLE m_hCompletionPort;
|
|
|
|
//
|
|
// shutdown event
|
|
//
|
|
HANDLE m_hShutdownEvent;
|
|
|
|
//
|
|
// array of worker thread handles
|
|
//
|
|
HANDLE* m_rgThrdpool;
|
|
|
|
//
|
|
// array of thread id's. BUGBUG: may be able to get rid of this if
|
|
// we have per thread handle
|
|
//
|
|
DWORD* m_rgdwThreadId;
|
|
|
|
//
|
|
// number of worker threads
|
|
//
|
|
DWORD m_dwNumThreads;
|
|
|
|
//
|
|
// max number of worker threads
|
|
//
|
|
DWORD m_dwMaxThreads;
|
|
|
|
//
|
|
// count work items in current job
|
|
//
|
|
LONG m_lWorkItems;
|
|
|
|
//
|
|
// event used to sync job completion
|
|
//
|
|
HANDLE m_hJobDone;
|
|
|
|
//
|
|
// context for current job
|
|
//
|
|
PVOID m_pvContext;
|
|
|
|
//
|
|
// crit sect to protect incs/decs to m_lWorkItems
|
|
//
|
|
CRITICAL_SECTION m_csCritItems;
|
|
|
|
//
|
|
// access completion port - needed by worker threads
|
|
//
|
|
HANDLE QueryCompletionPort() { return m_hCompletionPort; }
|
|
|
|
//
|
|
// thread function
|
|
//
|
|
static DWORD __stdcall ThreadDispatcher(PVOID pvWorkerThread);
|
|
};
|
|
|
|
#endif // #ifndef THRDPL2_H
|