hthread.h 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. #ifndef HV_THREAD_H_
  2. #define HV_THREAD_H_
  3. #include "hplatform.h"
  4. #ifdef OS_WIN
  5. #define hv_getpid (long)GetCurrentProcessId
  6. #else
  7. #define hv_getpid (long)getpid
  8. #endif
  9. #ifdef OS_WIN
  10. #define hv_gettid (long)GetCurrentThreadId
  11. #elif HAVE_GETTID || defined(OS_ANDROID)
  12. #define hv_gettid (long)gettid
  13. #elif defined(OS_LINUX)
  14. #include <sys/syscall.h>
  15. #define hv_gettid() (long)syscall(SYS_gettid)
  16. #elif defined(OS_DARWIN)
  17. static inline long hv_gettid() {
  18. uint64_t tid = 0;
  19. /* pthread_threadid_np is not available before 10.6 and in 10.6 for ppc */
  20. #if MAC_OS_X_VERSION_MIN_REQUIRED < 1060 || defined(__POWERPC__)
  21. tid = pthread_mach_thread_np(pthread_self());
  22. #else
  23. pthread_threadid_np(NULL, &tid);
  24. #endif
  25. return tid;
  26. }
  27. #elif HAVE_PTHREAD_H
  28. #define hv_gettid (long)pthread_self
  29. #else
  30. #define hv_gettid hv_getpid
  31. #endif
  32. /*
  33. #include "hthread.h"
  34. HTHREAD_ROUTINE(thread_demo) {
  35. printf("thread[%ld] start\n", hv_gettid());
  36. hv_delay(3000);
  37. printf("thread[%ld] end\n", hv_gettid());
  38. return 0;
  39. }
  40. int main() {
  41. hthread_t th = hthread_create(thread_demo, NULL);
  42. hthread_join(th);
  43. return 0;
  44. }
  45. */
  46. #ifdef OS_WIN
  47. typedef HANDLE hthread_t;
  48. typedef DWORD (WINAPI *hthread_routine)(void*);
  49. #define HTHREAD_RETTYPE DWORD
  50. #define HTHREAD_ROUTINE(fname) DWORD WINAPI fname(void* userdata)
  51. static inline hthread_t hthread_create(hthread_routine fn, void* userdata) {
  52. return CreateThread(NULL, 0, fn, userdata, 0, NULL);
  53. }
  54. static inline int hthread_join(hthread_t th) {
  55. WaitForSingleObject(th, INFINITE);
  56. CloseHandle(th);
  57. return 0;
  58. }
  59. #else
  60. typedef pthread_t hthread_t;
  61. typedef void* (*hthread_routine)(void*);
  62. #define HTHREAD_RETTYPE void*
  63. #define HTHREAD_ROUTINE(fname) void* fname(void* userdata)
  64. static inline hthread_t hthread_create(hthread_routine fn, void* userdata) {
  65. pthread_t th;
  66. pthread_create(&th, NULL, fn, userdata);
  67. return th;
  68. }
  69. static inline int hthread_join(hthread_t th) {
  70. return pthread_join(th, NULL);
  71. }
  72. #endif
  73. #ifdef __cplusplus
  74. /************************************************
  75. * HThread
  76. * Status: STOP,RUNNING,PAUSE
  77. * Control: start,stop,pause,resume
  78. * first-level virtual: doTask
  79. * second-level virtual: run
  80. ************************************************/
  81. #include <thread>
  82. #include <atomic>
  83. #include <chrono>
  84. class HThread {
  85. public:
  86. enum Status {
  87. STOP,
  88. RUNNING,
  89. PAUSE,
  90. };
  91. enum SleepPolicy {
  92. YIELD,
  93. SLEEP_FOR,
  94. SLEEP_UNTIL,
  95. NO_SLEEP,
  96. };
  97. HThread() {
  98. status = STOP;
  99. status_changed = false;
  100. dotask_cnt = 0;
  101. sleep_policy = YIELD;
  102. sleep_ms = 0;
  103. }
  104. virtual ~HThread() {}
  105. void setStatus(Status stat) {
  106. status_changed = true;
  107. status = stat;
  108. }
  109. void setSleepPolicy(SleepPolicy policy, uint32_t ms = 0) {
  110. sleep_policy = policy;
  111. sleep_ms = ms;
  112. setStatus(status);
  113. }
  114. virtual int start() {
  115. if (status == STOP) {
  116. thread = std::thread([this] {
  117. if (!doPrepare()) return;
  118. setStatus(RUNNING);
  119. run();
  120. setStatus(STOP);
  121. if (!doFinish()) return;
  122. });
  123. }
  124. return 0;
  125. }
  126. virtual int stop() {
  127. if (status != STOP) {
  128. setStatus(STOP);
  129. }
  130. if (thread.joinable()) {
  131. thread.join(); // wait thread exit
  132. }
  133. return 0;
  134. }
  135. virtual int pause() {
  136. if (status == RUNNING) {
  137. setStatus(PAUSE);
  138. }
  139. return 0;
  140. }
  141. virtual int resume() {
  142. if (status == PAUSE) {
  143. setStatus(RUNNING);
  144. }
  145. return 0;
  146. }
  147. virtual void run() {
  148. while (status != STOP) {
  149. while (status == PAUSE) {
  150. std::this_thread::yield();
  151. }
  152. doTask();
  153. ++dotask_cnt;
  154. HThread::sleep();
  155. }
  156. }
  157. virtual bool doPrepare() {return true;}
  158. virtual void doTask() {}
  159. virtual bool doFinish() {return true;}
  160. std::thread thread;
  161. std::atomic<Status> status;
  162. uint32_t dotask_cnt;
  163. protected:
  164. void sleep() {
  165. switch (sleep_policy) {
  166. case YIELD:
  167. std::this_thread::yield();
  168. break;
  169. case SLEEP_FOR:
  170. std::this_thread::sleep_for(std::chrono::milliseconds(sleep_ms));
  171. break;
  172. case SLEEP_UNTIL: {
  173. if (status_changed) {
  174. status_changed = false;
  175. base_tp = std::chrono::steady_clock::now();
  176. }
  177. base_tp += std::chrono::milliseconds(sleep_ms);
  178. std::this_thread::sleep_until(base_tp);
  179. }
  180. break;
  181. default: // donothing, go all out.
  182. break;
  183. }
  184. }
  185. SleepPolicy sleep_policy;
  186. uint32_t sleep_ms;
  187. // for SLEEP_UNTIL
  188. std::atomic<bool> status_changed;
  189. std::chrono::steady_clock::time_point base_tp;
  190. };
  191. #endif
  192. #endif // HV_THREAD_H_