thread.h 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. /*
  2. * Copyright (c) 2012-2014 Daniele Bartolini and individual contributors.
  3. * License: https://github.com/taylor001/crown/blob/master/LICENSE
  4. */
  5. #pragma once
  6. #include "config.h"
  7. #include "assert.h"
  8. #include "types.h"
  9. #include "semaphore.h"
  10. #if CROWN_PLATFORM_POSIX
  11. #include <pthread.h>
  12. #elif CROWN_PLATFORM_WINDOWS
  13. #include "win_headers.h"
  14. #include <process.h>
  15. #endif
  16. namespace crown
  17. {
  18. typedef int32_t (*ThreadFunction)(void*);
  19. struct Thread
  20. {
  21. Thread()
  22. #if CROWN_PLATFORM_POSIX
  23. : _handle(0)
  24. #elif CROWN_PLATFORM_WINDOWS
  25. : _handle(INVALID_HANDLE_VALUE)
  26. #endif
  27. , _function(NULL)
  28. , _data(NULL)
  29. , _stack_size(0)
  30. , _is_running(false)
  31. {
  32. }
  33. ~Thread()
  34. {
  35. if (_is_running)
  36. stop();
  37. }
  38. void start(ThreadFunction func, void* data = NULL, size_t stack_size = 0)
  39. {
  40. CE_ASSERT(!_is_running, "Thread is already running");
  41. CE_ASSERT(func != NULL, "Function must be != NULL");
  42. _function = func;
  43. _data = data;
  44. _stack_size = stack_size;
  45. #if CROWN_PLATFORM_POSIX
  46. pthread_attr_t attr;
  47. int result = pthread_attr_init(&attr);
  48. pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
  49. CE_ASSERT(result == 0, "pthread_attr_init: errno = %d", result);
  50. if (_stack_size != 0)
  51. {
  52. result = pthread_attr_setstacksize(&attr, _stack_size);
  53. CE_ASSERT(result == 0, "pthread_attr_setstacksize: errno = %d", result);
  54. }
  55. result = pthread_create(&_handle, &attr, thread_proc, this);
  56. CE_ASSERT(result == 0, "pthread_create: errno = %d", result);
  57. // Free attr memory
  58. result = pthread_attr_destroy(&attr);
  59. CE_ASSERT(result == 0, "pthread_attr_destroy: errno = %d", result);
  60. CE_UNUSED(result);
  61. #elif CROWN_PLATFORM_WINDOWS
  62. _handle = CreateThread(NULL, stack_size, Thread::thread_proc, this, 0, NULL);
  63. CE_ASSERT(_handle != NULL, "CreateThread: GetLastError = %d", GetLastError());
  64. #endif
  65. _is_running = true;
  66. _sem.wait();
  67. }
  68. void stop()
  69. {
  70. CE_ASSERT(_is_running, "Thread is not running");
  71. #if CROWN_PLATFORM_POSIX
  72. int result = pthread_join(_handle, NULL);
  73. CE_ASSERT(result == 0, "pthread_join: errno = %d", result);
  74. CE_UNUSED(result);
  75. _handle = 0;
  76. #elif CROWN_PLATFORM_WINDOWS
  77. WaitForSingleObject(_handle, INFINITE);
  78. // GetExitCodeThread(_handle, &m_exit_code);
  79. CloseHandle(_handle);
  80. _handle = INVALID_HANDLE_VALUE;
  81. #endif
  82. _is_running = false;
  83. }
  84. bool is_running()
  85. {
  86. return _is_running;
  87. }
  88. private:
  89. int32_t run()
  90. {
  91. _sem.post();
  92. return _function(_data);
  93. }
  94. #if CROWN_PLATFORM_POSIX
  95. static void* thread_proc(void* arg)
  96. {
  97. static int32_t result = -1;
  98. result = ((Thread*)arg)->run();
  99. return (void*)&result;
  100. }
  101. #elif CROWN_PLATFORM_WINDOWS
  102. static DWORD WINAPI thread_proc(void* arg)
  103. {
  104. Thread* thread = (Thread*) arg;
  105. int32_t result = thread->run();
  106. return result;
  107. }
  108. #endif
  109. private:
  110. #if CROWN_PLATFORM_POSIX
  111. pthread_t _handle;
  112. #elif CROWN_PLATFORM_WINDOWS
  113. HANDLE _handle;
  114. #endif
  115. ThreadFunction _function;
  116. void* _data;
  117. Semaphore _sem;
  118. size_t _stack_size;
  119. bool _is_running;
  120. private:
  121. // Disable copying
  122. Thread(const Thread&);
  123. Thread& operator=(const Thread&);
  124. };
  125. } // namespace crown