hthread.h 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. #ifndef HW_THREAD_H_
  2. #define HW_THREAD_H_
  3. #include "hplatform.h"
  4. #include "hdef.h"
  5. #ifdef OS_WIN
  6. #define gettid GetCurrentThreadId
  7. #elif defined(OS_ANDROID)
  8. #define gettid gettid
  9. #elif defined(OS_LINUX)
  10. #include <sys/syscall.h>
  11. static inline int gettid() {
  12. return syscall(SYS_gettid);
  13. }
  14. #elif HAVE_PTHREAD_H
  15. #define gettid pthread_self
  16. #endif
  17. #ifdef OS_WIN
  18. typedef HANDLE hthread_t;
  19. typedef DWORD (WINAPI *hthread_routine)(void*);
  20. #define HTHREAD_RETTYPE DWORD
  21. #define HTHREAD_ROUTINE(fname) DWORD WINAPI fname(void* userdata)
  22. static inline hthread_t hthread_create(hthread_routine fn, void* userdata) {
  23. return CreateThread(NULL, 0, fn, userdata, 0, NULL);
  24. }
  25. static inline int hthread_join(hthread_t th) {
  26. WaitForSingleObject(th, INFINITE);
  27. CloseHandle(th);
  28. return 0;
  29. }
  30. #else
  31. typedef pthread_t hthread_t;
  32. typedef void* (*hthread_routine)(void*);
  33. #define HTHREAD_RETTYPE void*
  34. #define HTHREAD_ROUTINE(fname) void* fname(void* userdata)
  35. static inline hthread_t hthread_create(hthread_routine fn, void* userdata) {
  36. pthread_t th;
  37. pthread_create(&th, NULL, fn, userdata);
  38. return th;
  39. }
  40. static inline int hthread_join(hthread_t th) {
  41. return pthread_join(th, NULL);
  42. }
  43. #endif
  44. #ifdef __cplusplus
  45. /************************************************
  46. * HThread
  47. * Status: STOP,RUNNING,PAUSE
  48. * Control: start,stop,pause,resume
  49. * first-level virtual: doTask
  50. * second-level virtual: run
  51. ************************************************/
  52. #include <thread>
  53. #include <atomic>
  54. #include <chrono>
  55. class HThread {
  56. public:
  57. HThread() {
  58. status = STOP;
  59. status_switch = false;
  60. sleep_policy = YIELD;
  61. sleep_ms = 0;
  62. }
  63. virtual ~HThread() {}
  64. virtual int start() {
  65. if (status == STOP) {
  66. switchStatus(RUNNING);
  67. dotask_cnt = 0;
  68. thread = std::thread([this] {
  69. if (!doPrepare()) return;
  70. run();
  71. if (!doFinish()) return;
  72. });
  73. }
  74. return 0;
  75. }
  76. virtual int stop() {
  77. if (status != STOP) {
  78. switchStatus(STOP);
  79. thread.join(); // wait thread exit
  80. }
  81. return 0;
  82. }
  83. virtual int pause() {
  84. if (status == RUNNING) {
  85. switchStatus(PAUSE);
  86. }
  87. return 0;
  88. }
  89. virtual int resume() {
  90. if (status == PAUSE) {
  91. switchStatus(RUNNING);
  92. }
  93. return 0;
  94. }
  95. virtual void run() {
  96. while (status != STOP) {
  97. while (status == PAUSE) {
  98. std::this_thread::yield();
  99. }
  100. doTask();
  101. dotask_cnt++;
  102. sleep();
  103. }
  104. }
  105. virtual bool doPrepare() {return true;}
  106. virtual void doTask() {}
  107. virtual bool doFinish() {return true;}
  108. std::thread thread;
  109. enum Status {
  110. STOP,
  111. RUNNING,
  112. PAUSE,
  113. };
  114. std::atomic<Status> status;
  115. uint32_t dotask_cnt;
  116. enum SleepPolicy {
  117. YIELD,
  118. SLEEP_FOR,
  119. SLEEP_UNTIL,
  120. NO_SLEEP,
  121. };
  122. void setSleepPolicy(SleepPolicy policy, uint32_t ms = 0) {
  123. status_switch = true;
  124. sleep_policy = policy;
  125. sleep_ms = ms;
  126. }
  127. protected:
  128. void switchStatus(Status stat) {
  129. status_switch = true;
  130. status = stat;
  131. }
  132. void sleep() {
  133. switch (sleep_policy) {
  134. case YIELD:
  135. std::this_thread::yield();
  136. break;
  137. case SLEEP_FOR:
  138. std::this_thread::sleep_for(std::chrono::milliseconds(sleep_ms));
  139. break;
  140. case SLEEP_UNTIL: {
  141. if (status_switch) {
  142. status_switch = false;
  143. base_tp = std::chrono::system_clock::now();
  144. }
  145. base_tp += std::chrono::milliseconds(sleep_ms);
  146. std::this_thread::sleep_until(base_tp);
  147. }
  148. break;
  149. default: // donothing, go all out.
  150. break;
  151. }
  152. }
  153. std::atomic<bool> status_switch;
  154. SleepPolicy sleep_policy;
  155. std::chrono::system_clock::time_point base_tp; // for SLEEP_UNTIL
  156. uint32_t sleep_ms;
  157. };
  158. #endif
  159. #endif // HW_THREAD_H_