Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

182 lines
4.0 KiB

  1. /*---------------------------------------------------------------------------
  2. File: TPooledDispatch.cpp
  3. Comments: Implementation of thread pool.
  4. (c) Copyright 1999, Mission Critical Software, Inc., All Rights Reserved
  5. Proprietary and confidential to Mission Critical Software, Inc.
  6. REVISION LOG ENTRY
  7. Revision By: Christy Boles
  8. Revised on 02/22/99 11:48:28
  9. ---------------------------------------------------------------------------
  10. */
  11. #ifdef USE_STDAFX
  12. #include "StdAfx.h"
  13. #else
  14. #include <windows.h>
  15. #endif
  16. #include "Common.hpp"
  17. #include "UString.hpp"
  18. #include "Tnode.hpp"
  19. #include "TPool.h"
  20. // maximum number of jobs allowed
  21. #define MAX_COUNT 5000000
  22. // executes a job from the thread pool
  23. int
  24. Job::Run()
  25. {
  26. MCSASSERT(m_pStartRoutine);
  27. m_Status = JobStatusRunning;
  28. m_ThreadID = GetCurrentThreadId();
  29. m_timeStarted = GetTickCount();
  30. m_result = (m_pStartRoutine)(m_pArgs);
  31. m_timeEnded = GetTickCount();
  32. m_Status = JobStatusFinished;
  33. return m_result;
  34. }
  35. // Thread entry point function used by all threads in the job pool
  36. // waits for a job and then executes it
  37. DWORD __stdcall
  38. ThreadEntryPoint(
  39. void * arg // in - pointer to job pool
  40. )
  41. {
  42. MCSASSERT(arg);
  43. TJobDispatcher * pPool = (TJobDispatcher *)arg;
  44. DWORD result = 0;
  45. BOOL bAbort = FALSE;
  46. do
  47. {
  48. if ( ! pPool->SignalForJob() )
  49. {
  50. // Now there should be a job waiting for us!
  51. Job * pJob = pPool->GetAvailableJob();
  52. if ( pJob )
  53. {
  54. result = pJob->Run();
  55. }
  56. else
  57. {
  58. bAbort = TRUE;
  59. }
  60. }
  61. else
  62. {
  63. result = (int)GetLastError();
  64. bAbort = TRUE;
  65. }
  66. }
  67. while ( ! bAbort );
  68. pPool->ThreadFinished();
  69. return result;
  70. }
  71. void
  72. TJobDispatcher::InitThreadPool(
  73. DWORD nThreads // in - number of threads to use
  74. )
  75. {
  76. BOOL bExisted;
  77. DWORD rc;
  78. DWORD ThreadID;
  79. HANDLE hThread;
  80. rc = m_sem.Create(NULL,0,MAX_COUNT, &bExisted);
  81. if ( ! rc && ! bExisted )
  82. {
  83. m_numThreads = nThreads;
  84. m_numActiveThreads = m_numThreads;
  85. // Construct the threads
  86. for ( UINT i = 0 ; i < nThreads ; i++ )
  87. {
  88. hThread = CreateThread(NULL,0,&ThreadEntryPoint,this,0,&ThreadID);
  89. CloseHandle(hThread);
  90. }
  91. }
  92. }
  93. DWORD // ret- OS return code
  94. TJobDispatcher::SignalForJob()
  95. {
  96. return m_sem.WaitSingle();
  97. }
  98. Job *
  99. TJobDispatcher::GetAvailableJob()
  100. {
  101. Job * pJob = NULL;
  102. if ( ! m_Aborting )
  103. {
  104. // get the first job from the 'waiting' list
  105. pJob = m_JobsWaiting.GetFirstJob();
  106. // and put it in the 'in progress' list
  107. if ( pJob )
  108. {
  109. m_JobsInProgress.InsertBottom(pJob);
  110. }
  111. else
  112. {
  113. MCSASSERT(m_JobsWaiting.Count() == 0);
  114. }
  115. }
  116. return pJob;
  117. }
  118. // Causes threads to stop when they finish their current job
  119. // any jobs that are waiting will not be executed.
  120. void
  121. TJobDispatcher::ShutdownThreads()
  122. {
  123. m_Aborting = TRUE;
  124. m_sem.Release(m_numThreads);
  125. // wait until all of our threads have exited, so we don't delete the thread pool out from under them.
  126. while ( m_numActiveThreads > 0 )
  127. {
  128. Sleep(100);
  129. }
  130. }
  131. // This function returns when all jobs are completed
  132. void TJobDispatcher::WaitForCompletion()
  133. {
  134. while ( UnfinishedJobs() )
  135. {
  136. Sleep(1000);
  137. }
  138. }
  139. // This functions returns the number of jobs that have not yet completed
  140. int
  141. TJobDispatcher::UnfinishedJobs()
  142. {
  143. int nUnfinished = 0;
  144. TNodeListEnum e;
  145. Job * j;
  146. nUnfinished += m_JobsWaiting.Count();
  147. for ( j = (Job*)e.OpenFirst(&m_JobsInProgress) ; j ; j = (Job*)e.Next() )
  148. {
  149. if ( j->GetStatus() != Job::JobStatusFinished )
  150. nUnfinished++;
  151. }
  152. return nUnfinished;
  153. }