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.

138 lines
2.7 KiB

  1. //
  2. // queue.h
  3. //
  4. #pragma once
  5. #include <limits.h>
  6. template <class T, LPTHREAD_START_ROUTINE lpThread>
  7. class CQueue
  8. {
  9. public:
  10. CQueue()
  11. : m_hShutdown(0),
  12. m_dwThreads(0)
  13. {
  14. m_sem = CreateSemaphore(
  15. NULL,
  16. 0, // initial count
  17. LONG_MAX,
  18. NULL);
  19. }
  20. // Wait
  21. //
  22. // This function will return false when the shutdown handle is set.
  23. //
  24. bool Wait(T& lhs)
  25. {
  26. HANDLE h[2] = {m_sem, m_hShutdown};
  27. DWORD n;
  28. n = m_hShutdown ? 2 : 1;
  29. if (0 == WaitForMultipleObjects(n, &h[0], FALSE, INFINITE))
  30. {
  31. EnterCriticalSection();
  32. lhs = m_dq.back();
  33. m_dq.pop_back();
  34. LeaveCriticalSection();
  35. return true;
  36. }
  37. else
  38. return false;
  39. }
  40. // GetItem
  41. //
  42. // This will return an item from the Q, or it will return false if empty.
  43. //
  44. bool GetItem(T& lhs)
  45. {
  46. bool rt;
  47. if (0 == WaitForSingleObject(m_sem, 0))
  48. {
  49. EnterCriticalSection();
  50. if (m_dq.empty())
  51. {
  52. rt = false;
  53. }
  54. else
  55. {
  56. lhs = m_dq.back();
  57. m_dq.pop_back();
  58. rt = true;
  59. }
  60. LeaveCriticalSection();
  61. return rt;
  62. }
  63. else
  64. {
  65. return false;
  66. }
  67. }
  68. // This now automatically creates worker threads.
  69. void push_front(const T& fifo)
  70. {
  71. DWORD dwQueue;
  72. DWORD dwThreadId;
  73. auto_leave cs(m_cs);
  74. //
  75. // Add to the work Q
  76. //
  77. cs.EnterCriticalSection();
  78. m_dq.push_front(fifo);
  79. //
  80. // Grab current work Q size to make sure we have enough threads
  81. //
  82. dwQueue = m_dq.size();
  83. cs.LeaveCriticalSection();
  84. //
  85. // Allocation method - Create as many threads as we need
  86. //
  87. while (dwQueue > m_dwThreads)
  88. {
  89. InterlockedIncrement((LPLONG)&m_dwThreads);
  90. m_vhThreads.push_back(
  91. CreateThread(NULL, 0, lpThread, NULL, 0, &dwThreadId));
  92. }
  93. ReleaseSemaphore(m_sem, 1, NULL);
  94. }
  95. void pop_back(T& lhs)
  96. {
  97. auto_leave cs(m_cs);
  98. cs.EnterCriticalSection();
  99. lhs = m_dq.back();
  100. m_dq.pop_back();
  101. }
  102. void EnterCriticalSection()
  103. { ::EnterCriticalSection(m_cs.get()); }
  104. void LeaveCriticalSection()
  105. { ::LeaveCriticalSection(m_cs.get()); }
  106. bool bTimeToShutdown()
  107. { return WAIT_TIMEOUT != WaitForSingleObject(m_hShutdown, 0); }
  108. HANDLE m_hShutdown;
  109. protected:
  110. deque <T> m_dq;
  111. auto_cs m_cs;
  112. HANDLE m_sem;
  113. DWORD m_dwThreads;
  114. vector<HANDLE> m_vhThreads;
  115. };