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.

296 lines
6.6 KiB

  1. /*******************************************************************************
  2. *
  3. * (C) COPYRIGHT MICROSOFT CORPORATION, 1998
  4. *
  5. * TITLE: TSPQUEUE.H
  6. *
  7. * VERSION: 1.0
  8. *
  9. * AUTHOR: ShaunIv
  10. *
  11. * DATE: 5/4/1999
  12. *
  13. * DESCRIPTION: Thread Safe Priority Queue template class
  14. *
  15. *******************************************************************************/
  16. #ifndef __TSPQUEUE_H_INCLUDED
  17. #define __TSPQUEUE_H_INCLUDED
  18. #include "simevent.h"
  19. #include "simcrit.h"
  20. #include "miscutil.h"
  21. template <class T>
  22. class CThreadSafePriorityQueue
  23. {
  24. public:
  25. enum
  26. {
  27. PriorityLow = 1,
  28. PriorityNormal = 2,
  29. PriorityHigh = 3,
  30. PriorityUrgent = 4
  31. };
  32. private:
  33. class CQueueNode
  34. {
  35. private:
  36. T *m_pData;
  37. int m_nPriority;
  38. CQueueNode *m_pNext;
  39. public:
  40. CQueueNode( T *pData, int nPriority=PriorityNormal )
  41. : m_pData(NULL), m_nPriority(nPriority), m_pNext(NULL)
  42. {
  43. m_pData = pData;
  44. }
  45. virtual ~CQueueNode(void)
  46. {
  47. if (m_pData)
  48. {
  49. delete m_pData;
  50. m_pData = NULL;
  51. }
  52. m_pNext = NULL;
  53. }
  54. const CQueueNode *Next(void) const
  55. {
  56. return m_pNext;
  57. }
  58. CQueueNode *Next(void)
  59. {
  60. return m_pNext;
  61. }
  62. CQueueNode *Next( CQueueNode *pNext )
  63. {
  64. return (m_pNext=pNext);
  65. }
  66. T *DetachData()
  67. {
  68. T *pResult = m_pData;
  69. m_pData = NULL;
  70. return pResult;
  71. }
  72. const T *Data(void) const
  73. {
  74. return m_pData;
  75. }
  76. T *Data(void)
  77. {
  78. return m_pData;
  79. }
  80. int Priority(void) const
  81. {
  82. return m_nPriority;
  83. }
  84. int Priority( int nPriority )
  85. {
  86. return (m_nPriority=nPriority);
  87. }
  88. };
  89. private:
  90. CQueueNode *m_pHead;
  91. mutable CSimpleCriticalSection m_CriticalSection;
  92. CSimpleEvent m_QueueEvent;
  93. CSimpleEvent m_PauseEvent;
  94. private:
  95. // No implementation
  96. CThreadSafePriorityQueue( const CThreadSafePriorityQueue & );
  97. CThreadSafePriorityQueue &operator=( const CThreadSafePriorityQueue & );
  98. public:
  99. CThreadSafePriorityQueue(void)
  100. : m_pHead(NULL)
  101. {
  102. m_QueueEvent.Reset();
  103. m_PauseEvent.Signal();
  104. }
  105. ~CThreadSafePriorityQueue(void)
  106. {
  107. CAutoCriticalSection cs(m_CriticalSection);
  108. while (m_pHead)
  109. {
  110. CQueueNode *pCurr = m_pHead;
  111. m_pHead = m_pHead->Next();
  112. delete pCurr;
  113. }
  114. }
  115. bool Empty( void ) const
  116. {
  117. CAutoCriticalSection cs(m_CriticalSection);
  118. return (NULL == m_pHead);
  119. }
  120. CQueueNode *Enqueue( T *pData, int nPriority=PriorityNormal )
  121. {
  122. //
  123. // Grab the critical section
  124. //
  125. CAutoCriticalSection cs(m_CriticalSection);
  126. //
  127. // Assume we will not be able to add a new item to the queue
  128. //
  129. CQueueNode *pResult = NULL;
  130. //
  131. // Make sure we have a valid data item
  132. //
  133. if (pData)
  134. {
  135. //
  136. // Try to allocate a new queue node
  137. //
  138. pResult = new CQueueNode(pData,nPriority);
  139. if (pResult)
  140. {
  141. //
  142. // This might be the first item in the queue
  143. //
  144. bool bMaybeSignal = Empty();
  145. //
  146. // If this is an empty queue or we need to do it right away, put it at the head of the queue
  147. //
  148. if (!m_pHead || pResult->Priority() >= PriorityUrgent)
  149. {
  150. pResult->Next(m_pHead);
  151. m_pHead = pResult;
  152. }
  153. else
  154. {
  155. //
  156. // Find the right place to put it
  157. //
  158. CQueueNode *pCurr = m_pHead;
  159. CQueueNode *pPrev = NULL;
  160. while (pCurr && pCurr->Priority() >= pResult->Priority())
  161. {
  162. pPrev = pCurr;
  163. pCurr = pCurr->Next();
  164. }
  165. //
  166. // Insert it in the proper place
  167. //
  168. if (pPrev)
  169. {
  170. pResult->Next(pCurr);
  171. pPrev->Next(pResult);
  172. }
  173. else
  174. {
  175. pResult->Next(m_pHead);
  176. m_pHead = pResult;
  177. }
  178. }
  179. //
  180. // If we were able to allocate the item, and the list isn't empty, signal the queue
  181. //
  182. if (bMaybeSignal && !Empty())
  183. {
  184. //
  185. // Got one!
  186. //
  187. Signal();
  188. //
  189. // Force a yield if this is a high priority message
  190. //
  191. if (pResult->Priority() >= PriorityHigh)
  192. {
  193. Sleep(0);
  194. }
  195. }
  196. }
  197. }
  198. return pResult;
  199. }
  200. T *Dequeue(void)
  201. {
  202. //
  203. // Grab the critical section
  204. //
  205. CAutoCriticalSection cs(m_CriticalSection);
  206. //
  207. // Wait until we are not paused
  208. //
  209. WiaUiUtil::MsgWaitForSingleObject( m_PauseEvent.Event(), INFINITE );
  210. //
  211. // If there are no items, return
  212. //
  213. if (Empty())
  214. {
  215. return NULL;
  216. }
  217. //
  218. // Grab the first item
  219. //
  220. CQueueNode *pFront = m_pHead;
  221. //
  222. // Advance to the next item
  223. //
  224. m_pHead = m_pHead->Next();
  225. //
  226. // Get the data
  227. //
  228. T *pResult = pFront->DetachData();
  229. //
  230. // Delete the queue item
  231. //
  232. delete pFront;
  233. //
  234. // If the queue is now empty, reset the event
  235. //
  236. if (Empty())
  237. {
  238. m_QueueEvent.Reset();
  239. }
  240. //
  241. // Return any data we got
  242. //
  243. return pResult;
  244. }
  245. void Pause(void)
  246. {
  247. m_PauseEvent.Reset();
  248. }
  249. void Resume(void)
  250. {
  251. m_PauseEvent.Signal();
  252. }
  253. void Signal(void)
  254. {
  255. m_QueueEvent.Signal();
  256. }
  257. HANDLE QueueEvent(void)
  258. {
  259. return m_QueueEvent.Event();
  260. }
  261. };
  262. #endif //__TSPQUEUE_H_INCLUDED