tpool.h (5482B)
1 /********************************** 2 * @author Johan Hanssen Seferidis 3 * License: MIT 4 * 5 **********************************/ 6 7 #pragma once 8 9 #if (__OpenBSD__) 10 // have to include pthread.h for pthread_mutex_t in OpenBSD with GCC 4.9.4 11 #include "pthread.h" 12 #endif 13 14 #ifdef __cplusplus 15 extern "C" { 16 #endif 17 18 // locks, max 512 threads 19 #define tpoolLockCount 512 20 extern pthread_mutex_t tpoolLocks[tpoolLockCount]; // only one thread can have the lock 21 22 // use lock in the tpoolLocks array 23 void tpoolLock(int position); 24 // unlock a lock in the tpoolLocks array 25 void tpoolUlock(int position); 26 27 typedef struct { 28 union { 29 char *s; 30 }; 31 union { 32 char *s2; 33 }; 34 // return value 35 union { 36 char **list; 37 int status; 38 }; 39 void (*cb)(void*); 40 void *cbArgs; 41 void *channel; 42 } tpoolArgs; 43 44 #define tpoolAdd(task, args) tpool_add_work(tpool, task, args) 45 #define tpoolWait tpool_wait(tpool) 46 #define tpoolKill tpool_destroy(tpool) 47 #define tpoolPause tpool_pause(tpool) 48 #define tpoolResume tpool_resume(tpool) 49 #define tpoolNum tpool_num_threads_working(tpool) 50 51 /* =================================== API ======================================= */ 52 53 54 typedef struct tpool_* threadpool; 55 extern threadpool tpool; 56 57 /** 58 * @brief Initialize threadpool 59 * 60 * Initializes a threadpool. This function will not return untill all 61 * threads have initialized successfully. 62 * 63 * @example 64 * 65 * .. 66 * threadpool tpool; //First we declare a threadpool 67 * tpool = tpool_init(4); //then we initialize it to 4 threads 68 * .. 69 * 70 * @param num_threads number of threads to be created in the threadpool 71 * @return threadpool created threadpool on success, 72 * NULL on error 73 */ 74 threadpool tpool_init(int num_threads); 75 76 77 /** 78 * @brief Add work to the job queue 79 * 80 * Takes an action and its argument and adds it to the threadpool's job queue. 81 * If you want to add to work a function with more than one arguments then 82 * a way to implement this is by passing a pointer to a structure. 83 * 84 * NOTICE: You have to cast both the function and argument to not get warnings. 85 * 86 * @example 87 * 88 * void print_num(int num){ 89 * printf("%d\n", num); 90 * } 91 * 92 * int main() { 93 * .. 94 * int a = 10; 95 * tpool_add_work(tpool, (void*)print_num, (void*)a); 96 * .. 97 * } 98 * 99 * @param threadpool threadpool to which the work will be added 100 * @param function_p pointer to function to add as work 101 * @param arg_p pointer to an argument 102 * @return 0 on successs, -1 otherwise. 103 */ 104 int tpool_add_work(threadpool, void (*function_p)(void*), void* arg_p); 105 106 107 /** 108 * @brief Wait for all queued jobs to finish 109 * 110 * Will wait for all jobs - both queued and currently running to finish. 111 * Once the queue is empty and all work has completed, the calling thread 112 * (probably the main program) will continue. 113 * 114 * Smart polling is used in wait. The polling is initially 0 - meaning that 115 * there is virtually no polling at all. If after 1 seconds the threads 116 * haven't finished, the polling interval starts growing exponentially 117 * untill it reaches max_secs seconds. Then it jumps down to a maximum polling 118 * interval assuming that heavy processing is being used in the threadpool. 119 * 120 * @example 121 * 122 * .. 123 * threadpool tpool = tpool_init(4); 124 * .. 125 * // Add a bunch of work 126 * .. 127 * tpool_wait(tpool); 128 * puts("All added work has finished"); 129 * .. 130 * 131 * @param threadpool the threadpool to wait for 132 * @return nothing 133 */ 134 void tpool_wait(threadpool); 135 136 137 /** 138 * @brief Pauses all threads immediately 139 * 140 * The threads will be paused no matter if they are idle or working. 141 * The threads return to their previous states once tpool_resume 142 * is called. 143 * 144 * While the thread is being paused, new work can be added. 145 * 146 * @example 147 * 148 * threadpool tpool = tpool_init(4); 149 * tpool_pause(tpool); 150 * .. 151 * // Add a bunch of work 152 * .. 153 * tpool_resume(tpool); // Let the threads start their magic 154 * 155 * @param threadpool the threadpool where the threads should be paused 156 * @return nothing 157 */ 158 void tpool_pause(threadpool); 159 160 161 /** 162 * @brief Unpauses all threads if they are paused 163 * 164 * @example 165 * .. 166 * tpool_pause(tpool); 167 * sleep(10); // Delay execution 10 seconds 168 * tpool_resume(tpool); 169 * .. 170 * 171 * @param threadpool the threadpool where the threads should be unpaused 172 * @return nothing 173 */ 174 void tpool_resume(threadpool); 175 176 177 /** 178 * @brief Destroy the threadpool 179 * 180 * This will wait for the currently active threads to finish and then 'kill' 181 * the whole threadpool to free up memory. 182 * 183 * @example 184 * int main() { 185 * threadpool tpool1 = tpool_init(2); 186 * threadpool tpool2 = tpool_init(2); 187 * .. 188 * tpool_destroy(tpool1); 189 * .. 190 * return 0; 191 * } 192 * 193 * @param threadpool the threadpool to destroy 194 * @return nothing 195 */ 196 void tpool_destroy(threadpool); 197 198 199 /** 200 * @brief Show currently working threads 201 * 202 * Working threads are the threads that are performing work (not idle). 203 * 204 * @example 205 * int main() { 206 * threadpool tpool1 = tpool_init(2); 207 * threadpool tpool2 = tpool_init(2); 208 * .. 209 * printf("Working threads: %d\n", tpool_num_threads_working(tpool1)); 210 * .. 211 * return 0; 212 * } 213 * 214 * @param threadpool the threadpool of interest 215 * @return integer number of threads working, -1 error 216 */ 217 int tpool_num_threads_working(threadpool); 218 219 220 #ifdef __cplusplus 221 } 222 #endif