hthread.h 5.5 KB

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