Windows2003-3790/inetsrv/iis/staxinc/export/thrdpl2.h
2020-09-30 16:53:55 +02:00

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