25'ten fazla konu seçemezsiniz Konular bir harf veya rakamla başlamalı, kısa çizgiler ('-') içerebilir ve en fazla 35 karakter uzunluğunda olabilir.
 
 
 

224 satır
5.6 KiB

  1. //
  2. // Lol Engine
  3. //
  4. // Copyright: (c) 2010-2011 Sam Hocevar <sam@hocevar.net>
  5. // This program is free software; you can redistribute it and/or
  6. // modify it under the terms of the Do What The Fuck You Want To
  7. // Public License, Version 2, as published by Sam Hocevar. See
  8. // http://sam.zoy.org/projects/COPYING.WTFPL for more details.
  9. //
  10. //
  11. // The ThreadBase class
  12. // --------------------
  13. //
  14. #if !defined __LOL_THREADBASE_H__
  15. #define __LOL_THREADBASE_H__
  16. #if defined __linux__ || defined __native_client__
  17. # include <pthread.h>
  18. #elif defined _WIN32
  19. # include <windows.h>
  20. #else
  21. # error No threading support yet :(
  22. #endif
  23. namespace lol
  24. {
  25. class MutexBase
  26. {
  27. public:
  28. MutexBase()
  29. {
  30. #if defined __linux__ || defined __native_client__
  31. pthread_mutex_init(&m_mutex, NULL);
  32. #elif defined _WIN32
  33. InitializeCriticalSection(&m_mutex);
  34. #endif
  35. }
  36. ~MutexBase()
  37. {
  38. #if defined __linux__ || defined __native_client__
  39. pthread_mutex_destroy(&m_mutex);
  40. #elif defined _WIN32
  41. DeleteCriticalSection(&m_mutex);
  42. #endif
  43. }
  44. void Lock()
  45. {
  46. #if defined __linux__ || defined __native_client__
  47. pthread_mutex_lock(&m_mutex);
  48. #elif defined _WIN32
  49. EnterCriticalSection(&m_mutex);
  50. #endif
  51. }
  52. void Unlock()
  53. {
  54. #if defined __linux__ || defined __native_client__
  55. pthread_mutex_unlock(&m_mutex);
  56. #elif defined _WIN32
  57. LeaveCriticalSection(&m_mutex);
  58. #endif
  59. }
  60. private:
  61. #if defined __linux__ || defined __native_client__
  62. pthread_mutex_t m_mutex;
  63. #elif defined _WIN32
  64. CRITICAL_SECTION m_mutex;
  65. #endif
  66. };
  67. class QueueBase
  68. {
  69. public:
  70. QueueBase()
  71. {
  72. m_start = m_count = 0;
  73. #if defined __linux__ || defined __native_client__
  74. m_poppers = m_pushers = 0;
  75. pthread_mutex_init(&m_mutex, NULL);
  76. pthread_cond_init(&m_empty_cond, NULL);
  77. pthread_cond_init(&m_full_cond, NULL);
  78. #elif defined _WIN32
  79. m_empty_sem = CreateSemaphore(NULL, CAPACITY, CAPACITY, NULL);
  80. m_full_sem = CreateSemaphore(NULL, 0, CAPACITY, NULL);
  81. InitializeCriticalSection(&m_mutex);
  82. #endif
  83. }
  84. ~QueueBase()
  85. {
  86. #if defined __linux__ || defined __native_client__
  87. pthread_cond_destroy(&m_empty_cond);
  88. pthread_cond_destroy(&m_full_cond);
  89. pthread_mutex_destroy(&m_mutex);
  90. #elif defined _WIN32
  91. CloseHandle(m_empty_sem);
  92. CloseHandle(m_full_sem);
  93. DeleteCriticalSection(&m_mutex);
  94. #endif
  95. }
  96. void Push(int value)
  97. {
  98. #if defined __linux__ || defined __native_client__
  99. pthread_mutex_lock(&m_mutex);
  100. /* If queue is full, wait on the "full" cond var. */
  101. m_pushers++;
  102. while (m_count == CAPACITY)
  103. pthread_cond_wait(&m_full_cond, &m_mutex);
  104. m_pushers--;
  105. #elif defined _WIN32
  106. WaitForSingleObject(m_empty_sem, INFINITE);
  107. EnterCriticalSection(&m_mutex);
  108. #endif
  109. /* Push value */
  110. m_values[(m_start + m_count) % CAPACITY] = value;
  111. m_count++;
  112. #if defined __linux__ || defined __native_client__
  113. /* If there were poppers waiting, signal the "empty" cond var. */
  114. if (m_poppers)
  115. pthread_cond_signal(&m_empty_cond);
  116. pthread_mutex_unlock(&m_mutex);
  117. #elif defined _WIN32
  118. LeaveCriticalSection(&m_mutex);
  119. ReleaseSemaphore(m_full_sem, 1, NULL);
  120. #endif
  121. }
  122. int Pop()
  123. {
  124. #if defined __linux__ || defined __native_client__
  125. pthread_mutex_lock(&m_mutex);
  126. /* Wait until there is something in the queue. Be careful, we
  127. * could get woken up but another thread may have eaten the
  128. * message in the meantime. */
  129. m_poppers++;
  130. while (m_count == 0)
  131. pthread_cond_wait(&m_empty_cond, &m_mutex);
  132. m_poppers--;
  133. #elif defined _WIN32
  134. WaitForSingleObject(m_full_sem, INFINITE);
  135. EnterCriticalSection(&m_mutex);
  136. #endif
  137. /* Pop value */
  138. int ret = m_values[m_start];
  139. m_start = (m_start + 1) % CAPACITY;
  140. m_count--;
  141. #if defined __linux__ || defined __native_client__
  142. /* If there were pushers waiting, signal the "full" cond var. */
  143. if (m_pushers)
  144. pthread_cond_signal(&m_full_cond);
  145. pthread_mutex_unlock(&m_mutex);
  146. #else
  147. LeaveCriticalSection(&m_mutex);
  148. ReleaseSemaphore(m_empty_sem, 1, NULL);
  149. #endif
  150. return ret;
  151. }
  152. private:
  153. static size_t const CAPACITY = 100;
  154. int m_values[CAPACITY];
  155. size_t m_start, m_count;
  156. #if defined __linux__ || defined __native_client__
  157. size_t m_poppers, m_pushers;
  158. pthread_mutex_t m_mutex;
  159. pthread_cond_t m_empty_cond, m_full_cond;
  160. #elif defined _WIN32
  161. HANDLE m_empty_sem, m_full_sem;
  162. CRITICAL_SECTION m_mutex;
  163. #endif
  164. };
  165. class ThreadBase
  166. {
  167. public:
  168. ThreadBase(void *(*fn)(void *), void *data)
  169. {
  170. #if defined __linux__ || defined __native_client__
  171. /* Set the joinable attribute for systems who don't play nice */
  172. pthread_attr_t attr;
  173. pthread_attr_init(&attr);
  174. pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
  175. pthread_create(&m_thread, &attr, fn, data);
  176. #elif defined _WIN32
  177. m_thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)fn,
  178. data, 0, &m_tid);
  179. #endif
  180. }
  181. virtual ~ThreadBase()
  182. {
  183. #if defined __linux__ || defined __native_client__
  184. pthread_join(m_thread, NULL);
  185. #elif defined _WIN32
  186. WaitForSingleObject(m_thread, INFINITE);
  187. #endif
  188. }
  189. private:
  190. #if defined __linux__ || defined __native_client__
  191. pthread_t m_thread;
  192. #elif defined _WIN32
  193. HANDLE m_thread;
  194. DWORD m_tid;
  195. #endif
  196. };
  197. } /* namespace lol */
  198. #endif // __LOL_THREADBASE_H__