hthread.h 4.7 KB

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