windows-nt/Source/XPSP1/NT/admin/admt/disp/tpool.cpp

183 lines
4 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*---------------------------------------------------------------------------
File: TPooledDispatch.cpp
Comments: Implementation of thread pool.
(c) Copyright 1999, Mission Critical Software, Inc., All Rights Reserved
Proprietary and confidential to Mission Critical Software, Inc.
REVISION LOG ENTRY
Revision By: Christy Boles
Revised on 02/22/99 11:48:28
---------------------------------------------------------------------------
*/
#ifdef USE_STDAFX
#include "StdAfx.h"
#else
#include <windows.h>
#endif
#include "Common.hpp"
#include "UString.hpp"
#include "Tnode.hpp"
#include "TPool.h"
// maximum number of jobs allowed
#define MAX_COUNT 5000000
// executes a job from the thread pool
int
Job::Run()
{
MCSASSERT(m_pStartRoutine);
m_Status = JobStatusRunning;
m_ThreadID = GetCurrentThreadId();
m_timeStarted = GetTickCount();
m_result = (m_pStartRoutine)(m_pArgs);
m_timeEnded = GetTickCount();
m_Status = JobStatusFinished;
return m_result;
}
// Thread entry point function used by all threads in the job pool
// waits for a job and then executes it
DWORD __stdcall
ThreadEntryPoint(
void * arg // in - pointer to job pool
)
{
MCSASSERT(arg);
TJobDispatcher * pPool = (TJobDispatcher *)arg;
DWORD result = 0;
BOOL bAbort = FALSE;
do
{
if ( ! pPool->SignalForJob() )
{
// Now there should be a job waiting for us!
Job * pJob = pPool->GetAvailableJob();
if ( pJob )
{
result = pJob->Run();
}
else
{
bAbort = TRUE;
}
}
else
{
result = (int)GetLastError();
bAbort = TRUE;
}
}
while ( ! bAbort );
pPool->ThreadFinished();
return result;
}
void
TJobDispatcher::InitThreadPool(
DWORD nThreads // in - number of threads to use
)
{
BOOL bExisted;
DWORD rc;
DWORD ThreadID;
HANDLE hThread;
rc = m_sem.Create(NULL,0,MAX_COUNT, &bExisted);
if ( ! rc && ! bExisted )
{
m_numThreads = nThreads;
m_numActiveThreads = m_numThreads;
// Construct the threads
for ( UINT i = 0 ; i < nThreads ; i++ )
{
hThread = CreateThread(NULL,0,&ThreadEntryPoint,this,0,&ThreadID);
CloseHandle(hThread);
}
}
}
DWORD // ret- OS return code
TJobDispatcher::SignalForJob()
{
return m_sem.WaitSingle();
}
Job *
TJobDispatcher::GetAvailableJob()
{
Job * pJob = NULL;
if ( ! m_Aborting )
{
// get the first job from the 'waiting' list
pJob = m_JobsWaiting.GetFirstJob();
// and put it in the 'in progress' list
if ( pJob )
{
m_JobsInProgress.InsertBottom(pJob);
}
else
{
MCSASSERT(m_JobsWaiting.Count() == 0);
}
}
return pJob;
}
// Causes threads to stop when they finish their current job
// any jobs that are waiting will not be executed.
void
TJobDispatcher::ShutdownThreads()
{
m_Aborting = TRUE;
m_sem.Release(m_numThreads);
// wait until all of our threads have exited, so we don't delete the thread pool out from under them.
while ( m_numActiveThreads > 0 )
{
Sleep(100);
}
}
// This function returns when all jobs are completed
void TJobDispatcher::WaitForCompletion()
{
while ( UnfinishedJobs() )
{
Sleep(1000);
}
}
// This functions returns the number of jobs that have not yet completed
int
TJobDispatcher::UnfinishedJobs()
{
int nUnfinished = 0;
TNodeListEnum e;
Job * j;
nUnfinished += m_JobsWaiting.Count();
for ( j = (Job*)e.OpenFirst(&m_JobsInProgress) ; j ; j = (Job*)e.Next() )
{
if ( j->GetStatus() != Job::JobStatusFinished )
nUnfinished++;
}
return nUnfinished;
}