linux下线程相关概念以及函数介绍:
互斥锁:
pthread_mutex_t fastmutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t recmutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
pthread_mutex_t errchkmutex = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP;
mutex(互斥锁)是用于保护共享数据结构不受并发修改影响的锁,其还可用于保护程序关键部分。mutex可以有2种状态,unlocked(不被任何线程拥有),locked(被一个线程拥有)。一个mutex不能同时被两个不同的线程所拥有。如果线程A试图去加锁一个已经被线程B锁定的的mutex,则此线程A会阻塞直至线程B对mutex进行解锁操作后。
mutex操作函数:
int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr);
pthread_mutex_init()函数使用mutexattr属性初始化mutex指针所指向的mutex,如果mutexattr=NULL,则使用默认属性初始化mutex.linux线程只支持一个mutex属性,此属性的种类可以是fast,recursive,error checking。属性的种类决定此mutex是否可以被已经拥有此mutex的线程再次加锁。默认属性的种类是fast.
mutex也可使用
PTHREAD_MUTEX_INITIALIZER直接进行静态初始化为mutex属性是fast的互斥锁,也可使用PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP直接进行静态初始化为mutex属性是recursive类型的互斥锁,也可使用PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP直接进行静态初始化为mutex属性是error checking类型的互斥锁。
int pthread_mutex_lock(pthread_mutex_t *mutex);
锁定mutex.如果mutex当前是unlocked状态,则mutex的状态将由调用
pthread_mutex_lock的线程修改为locked,且此时
pthread_mutex_lock立即返回;
如果mutex当前是locked状态(已经由别的线程加锁),则
pthread_mutex_lock挂起调用
pthread_mutex_lock的线程直至,mutex被解锁(默认行为)。
如果mutex当前是locked状态(已经由别的线程加锁),则
pthread_mutex_lock的行为由mutex的属性所决定。
mutex的属性是fast:调用
pthread_mutex_lock会挂起直至mutex被解锁。
从而导致调用
pthread_mutex_lock的线程发生死锁。
mutex的属性是
recursive
:
pthread_mutex_lock会成功并立即返回,并记录调用
pthread_mutex_lock锁定互斥锁的次数。在mutex返回到解锁状态前,必须执行相同次数的
pthread_mutex_unlock.
mutex的属性是
error checking
:
pthread_mutex_lock会带有错误码EDEADLK立即返回。
int pthread_mutex_trylock(pthread_mutex_t *mutex);
pthr
ead_mutex_trylock与 pthread_mutex_lock是相同的,如果互斥锁已经被另外的线程锁定,pthread_mutex_trulock不会阻塞线程,而是立即返回,并返回错误代码EBUSY.
int pthread_mutex_unlock(pthread_mutex_t *mutex);
pthread_mutex_unlock解锁给定的mutex.在执行pthread_mutex_unlock的时候。所给定的mutex假定为已经被调用pthread_mutex_unlock的线程锁定。如果mutex的属性是fast,pthread_mutex_unlock总是返回unlocked状态的mutex;如果mutex的属性是recursive,pthread_mutex_unlock会降低mutex被锁定的次数,只有当此个数为0的时候,mutex才真正被解锁。在mutex的属性是error checking和recursive的时候,pthread_mutex_unlock会在运行时检查mutex是否锁定,并且判断mutex是否被调用pthread_mutex_unlock的同一线程锁定,之后才会调用pthread_mutex_unlock。如果条件都不满足,则返回错误代码。mutex的属性是fast在调用pthread_mutex_unlock的不会做这些检查,因此允许被锁定的互斥锁由其所有者以外的线程解锁。这是不可移植,不能依赖。
int pthread_mutex_destroy(pthread_mutex_t *mutex);
pthread_mutex_destroy销毁mutex,释放资源。在调用此函数前mutex必须是unlock的。在linux线程中,mutex与资源无关。pthread_mutex_destroy实际上只是检查mutex是否被解锁。
取消 :
互斥锁的操作函数中没有取消操作。pthread_mutex_lock也不是。尽管此函数可以挂起一个线程来执行任意时间,这种情况下互斥锁的取消是可预测的,允许取消处理去精确地解锁那些需要在程序停止前解锁的互斥锁,。。因此先吃使用延迟取消使得不能在长时间保留互斥锁。
异步信号安全:
互斥操作函数不是异步信号安全的,这意味着它们不应该在信号处理程序中调用。特别是在信号处理程序中去调用pthread_mutex_lock或者pthread_mutex_unlock,这样可能会造成线程死锁。
返回值:
pthread_mutex_init总是返回0,其他函数在执行成功的时候返回0,执行失败的时候返回错误码。
错误码:
函数 | 错误码 | 说明 |
pthread_mutex_lock | EINVAL | mutex未正确初始化 |
EDEADLK | mutex(只有初始化为error check类型)已经加锁 | |
pthread_mutex_trylock | EBUSY | mutex不能获取,因为其已经被锁定 |
EINVAL | mutex未正确初始化 | |
pthread_mutex_unlock | EINVAL | mutex未正确初始化 |
EPERM | 调用线程不是锁定mutex的线程(mutex初始化为error check) | |
pthread_mutex_destory | EBUSY | mutex已经被锁定 |
条件变量:
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
条件变量是一种同步机制。其可以使线程暂停执行并释放cpu时间直到共享数据上的某个判断条件得以满足。条件变量的基本操作:当待判断的条件得以满足的时候向条件变量发送信号,然后等待条件变量,原来暂停的线程得以再次执行,直到另一个条件。为防止竞争,条件变量必须和互斥锁相关联。
int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *cond_attr);
pthread_cond_init
使用cond_attr属性初始化条件变量cond。如果cond_attr是NULL则使用默认属性初始化cond.linux线程对于条件变量不支持任何属性,因此linux在实际处理的时候是忽略属性的。pthread_cond_t也可使用PTHREAD_COND_INITIALIZER去进行静态初始化。
int pthread_cond_signal(pthread_cond_t *cond);
pthread_cond_signal启动一个正在等待条件变量cond的线程。如果没有线程在等待cond则不会发生任何事。如果有多个线程同时在等待cond,实际上只有一个线程启动,但是并不指定哪一个。
int pthread_cond_broadcast(pthread_cond_t *cond);
pthread_cond_broadcast启动所有正在等待条件变量cond的线程。如果没有线程在等待cond则不会发生任何事。
pthread_cond_broadcast启动所有正在等待条件变量cond的线程。如果没有线程在等待cond则不会发生任何事。
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
pthread_cond_wait自动解锁mutex(等同于调用了pthread_mutex_unlock)并等待cond信号被触发(signal)。在调用此函数后,且cond未触发的时候,调用此函数的线程会阻塞,且不会占用任何CPU时间。在调用pthread_cond_wait之前mutex必须是加锁的。在cond条件触发的时候并且在返回到调用线程前,pthread_cond_wait会再次为mutex加锁。解锁以及线程挂起等待条件变量的操作是原子的,因此如果所有线程总是在发出条件变量信号前对互斥锁加锁,就保证了在线程锁定互斥锁和等待条件变量之间,条件是不能被标记的。这就意味着开发者在调用pthread_cond_wait后的处理代码中仍需要添加与之对应的mutex的解锁代码,否则会造成线程死锁。
int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime);
pthread_cond_timedwait和
pthread_cond_wait一样会
自动解锁mutex,并等待cond。但是其使用abstime限制了等待cond的时间。如果条件cond在abstime所设置的事件内未触发,
pthread_cond_timedwait会再次加锁mutex并返回错误码ETIMEDOUT。
abstime参数指定了一个绝对时间,使用time(),gettimeofday()去获取此时间是相同的,如果abstime=0,则代表了1970年1月1日00:00:00
int pthread_cond_destroy(pthread_cond_t *cond);
pthread_cond_destroy销毁一个条件变量cond.如果cond占有资源则释放资源。在调用此函数前必须保证没有线程在等待cond这个条件变量。在linux线程实现中没有cond是没有资源占用的。因此在linux下
pthread_cond_destroy只是在判断是否有线程在等待此条件变量cond.
取消 :
pthread_cond_timedwait()和
pthread_cond_wait
()是取消点。如果一个线程在挂起在
pthread_cond_timedwait,
pthread_cond_wait
这些函数的时候被取消,则线程立即恢复执行,然后再次将mutex加锁到
这些函数,最后执行取消。因此清理处理程序必须确保mutex是在加锁状态。
异步信号安全:
互斥操作函数不是异步信号安全的,这意味着它们不应该在信号处理程序中调用。特别是在信号处理程序中去调用pthread_cond_signal或者pthread_cond_broadcast,这样可能会造成线程死锁。
返回值:
所有函数在执行成功的时候返回0,执行失败的时候返回错误码。
错误:
函数 | 错误码 | 说明 |
pthread_cond_timedwait | ETIMEDOUT | 直到abstime所指定的时间,cond还未被触发 |
EINTR | pthread_cond_timedwait被信号打断 | |
pthread_cond_destroy | EBUSY | 有线程正在等待cond条件 |
实例源码一:
1 /************************************threadpool.h***************************************************/ 2 #ifndef __THREADPOOL_H_ 3 #define __THREADPOOL_H_ 4 typedef struct threadpool_t threadpool_t; 5 /*创建线程池*/ 6 threadpool_t *threadpool_create(int min_thr_num, int max_thr_num, int queue_max_size); 7 /*释放线程池*/ 8 int threadpool_free(threadpool_t *pool); 9 /*销毁线程池*/ 10 int threadpool_destroy(threadpool_t *pool); 11 /*管理线程*/ 12 void *admin_thread(void *threadpool); 13 /*线程是否存在*/ 14 //int is_thread_alive(pthread_t tid); 15 /*工作线程*/ 16 void *threadpool_thread(void *threadpool); 17 /*向线程池的任务队列中添加一个任务*/ 18 int threadpool_add_task(threadpool_t *pool, void *(*function)(void *arg), void *arg); 19 #endif
1 /************************************threadpool.c***************************************************/ 2 #include "threadpool.h" 3 #include <stdio.h> 4 #include <stdlib.h> 5 #include <pthread.h> 6 #include <signal.h> 7 #include <assert.h> 8 #include <string.h> 9 #include <errno.h> 10 11 #define DEFAULT_TIME 1 /*默认时间10s*/ 12 #define MIN_WAIT_TASK_NUM 10 /*当任务数超过了它,就该添加新线程了*/ 13 #define DEFAULT_THREAD_NUM 10 /*每次创建或销毁的线程个数*/ 14 #define true 1 15 #define false 0 16 17 18 /*任务*/ 19 typedef struct { 20 void *(*function)(void *); 21 void *arg; 22 } threadpool_task_t; 23 24 /*线程池管理*/ 25 struct threadpool_t{ 26 pthread_mutex_t lock; /* 锁住整个结构体 */ 27 pthread_mutex_t thread_counter; /* 用于使用忙线程数时的锁 */ 28 pthread_cond_t queue_not_full; /* 条件变量,任务队列不为满 */ 29 pthread_cond_t queue_not_empty; /* 任务队列不为空 */ 30 31 pthread_t *threads; /* 存放线程的tid,实际上就是管理了线 数组 */ 32 pthread_t admin_tid; /* 管理者线程tid */ 33 threadpool_task_t *task_queue; /* 任务队列 */ 34 35 /*线程池信息*/ 36 int min_thr_num; /* 线程池中最小线程数 */ 37 int max_thr_num; /* 线程池中最大线程数 */ 38 int live_thr_num; /* 线程池中存活的线程数 */ 39 int busy_thr_num; /* 忙线程,正在工作的线程 */ 40 int wait_exit_thr_num; /* 需要销毁的线程数 */ 41 42 /*任务队列信息*/ 43 int queue_front; /* 队头 */ 44 int queue_rear; /* 队尾 */ 45 int queue_size; 46 47 /* 存在的任务数 */ 48 int queue_max_size; /* 队列能容纳的最大任务数 */ 49 50 /*状态*/ 51 int shutdown; /* true为关闭 */ 52 }; 53 54 55 /* 函数原型 */ 56 57 /*创建线程池*/ 58 threadpool_t *threadpool_create(int min_thr_num, int max_thr_num, int queue_max_size); 59 /*释放线程池*/ 60 int threadpool_free(threadpool_t *pool); 61 /*销毁线程池*/ 62 int threadpool_destroy(threadpool_t *pool); 63 /*管理线程*/ 64 void *admin_thread(void *threadpool); 65 /*线程是否存在*/ 66 int is_thread_alive(pthread_t tid); 67 /*工作线程*/ 68 void *threadpool_thread(void *threadpool); 69 /*向线程池的任务队列中添加一个任务*/ 70 int threadpool_add_task(threadpool_t *pool, void *(*function)(void *arg), void *arg); 71 72 /* */ 73 74 75 /*创建线程池*/ 76 threadpool_t * 77 threadpool_create(int min_thr_num, int max_thr_num, int queue_max_size) 78 { 79 int i; 80 threadpool_t *pool = NULL; 81 do 82 { 83 if ((pool=(threadpool_t *)malloc(sizeof(threadpool_t))) == NULL) 84 { 85 printf("malloc threadpool false; \n"); 86 break; 87 } 88 /*信息初始化*/ 89 pool->min_thr_num = min_thr_num; 90 pool->max_thr_num = max_thr_num; 91 pool->busy_thr_num = 0; 92 pool->live_thr_num = min_thr_num; 93 pool->wait_exit_thr_num = 0; 94 pool->queue_front = 0; 95 pool->queue_rear = 0; 96 pool->queue_size = 0; 97 pool->queue_max_size = queue_max_size; 98 pool->shutdown = false; 99 100 /*根据最大线程数,给工作线程数组开空间,清0*/ 101 pool->threads = (pthread_t *)malloc(sizeof(pthread_t)*max_thr_num);//根据线程池中最多容纳的线程数创建线程数组 102 if (pool->threads == NULL) 103 { 104 printf("malloc threads false;\n"); 105 break; 106 } 107 memset(pool->threads, 0, sizeof(pthread_t)*max_thr_num); 108 109 /*队列开空间*/ 110 pool->task_queue = 111 (threadpool_task_t *)malloc(sizeof(threadpool_task_t)*queue_max_size);//根据人物队列中最多容纳的任务数创建线任务数组 112 if (pool->task_queue == NULL) 113 { 114 printf("malloc task queue false;\n"); 115 break; 116 } 117 118 /*初始化互斥锁和条件变量*/ 119 if ( pthread_mutex_init(&(pool->lock), NULL) != 0 || 120 pthread_mutex_init(&(pool->thread_counter), NULL) !=0 || 121 pthread_cond_init(&(pool->queue_not_empty), NULL) !=0 || 122 pthread_cond_init(&(pool->queue_not_full), NULL) !=0) 123 { 124 printf("init lock or cond false;\n"); 125 break; 126 } 127 128 /*启动min_thr_num个工作线程*/ 129 for (i=0; i<min_thr_num; i++) 130 { 131 /*pool指向当前线程池*/ 132 pthread_create(&(pool->threads[i]), NULL, threadpool_thread, (void *)pool);///依据线程池中的最小线程数去创建线程 133 printf("start thread 0x%x... \n", (unsigned int)pool->threads[i]); 134 } 135 /*管理者线程*/ 136 pthread_create(&(pool->admin_tid), NULL, admin_thread, (void *)pool);///创建管理者线程 137 138 return pool;//返回创建好的线程池 139 } while(0); 140 141 /*释放pool的空间*/ 142 threadpool_free(pool); 143 return NULL; 144 } 145 146 /*释放线程池*/ 147 int 148 threadpool_free(threadpool_t *pool) 149 { 150 if (pool == NULL) 151 { 152 return -1; 153 } 154 155 if (pool->task_queue) 156 { 157 free(pool->task_queue); 158 } 159 if (pool->threads) 160 { 161 free(pool->threads); 162 pthread_mutex_lock(&(pool->lock)); /*先锁住再销毁*/ 163 pthread_mutex_destroy(&(pool->lock)); 164 pthread_mutex_lock(&(pool->thread_counter)); 165 pthread_mutex_destroy(&(pool->thread_counter)); 166 pthread_cond_destroy(&(pool->queue_not_empty)); 167 pthread_cond_destroy(&(pool->queue_not_full)); 168 } 169 free(pool); 170 pool = NULL; 171 172 return 0; 173 } 174 175 /*销毁线程池*/ 176 int 177 threadpool_destroy(threadpool_t *pool) 178 { 179 int i; 180 if (pool == NULL) 181 { 182 return -1; 183 } 184 pool->shutdown = true; 185 186 /*销毁管理者线程*/ 187 pthread_join(pool->admin_tid, NULL); 188 189 //通知所有线程去自杀(在自己领任务的过程中) 190 for (i=0; i<pool->live_thr_num; i++) 191 { 192 pthread_cond_broadcast(&(pool->queue_not_empty)); 193 } 194 195 /*等待线程结束 先是pthread_exit 然后等待其结束*/ 196 for (i=0; i<pool->live_thr_num; i++) 197 { 198 pthread_join(pool->threads[i], NULL); 199 } 200 201 threadpool_free(pool); 202 return 0; 203 } 204 205 /*管理线程*/ 206 void * 207 admin_thread(void *threadpool) 208 { 209 int i; 210 threadpool_t *pool = (threadpool_t *)threadpool; 211 while (!pool->shutdown) 212 { 213 printf("admin -----------------\n"); 214 sleep(DEFAULT_TIME); /*隔一段时间再管理*/ 215 pthread_mutex_lock(&(pool->lock)); /*加锁*/ 216 int queue_size = pool->queue_size; /*任务数*/ 217 int live_thr_num = pool->live_thr_num; /*存活的线程数*/ 218 pthread_mutex_unlock(&(pool->lock)); /*解锁*/ 219 220 pthread_mutex_lock(&(pool->thread_counter)); 221 int busy_thr_num = pool->busy_thr_num; /*忙线程数*/ 222 pthread_mutex_unlock(&(pool->thread_counter)); 223 224 printf("admin busy live -%d--%d-\n", busy_thr_num, live_thr_num); 225 /*创建新线程 实际任务数量大于 最小正在等待的任务数量,存活线程数小于最大线程数*/ 226 if (queue_size >= MIN_WAIT_TASK_NUM && live_thr_num <= pool->max_thr_num) 227 { 228 printf("admin add-----------\n"); 229 pthread_mutex_lock(&(pool->lock)); 230 int add=0; 231 232 /*一次增加 DEFAULT_THREAD_NUM 个线程*/ 233 for (i=0; i<pool->max_thr_num && add<DEFAULT_THREAD_NUM 234 && pool->live_thr_num < pool->max_thr_num; i++) 235 { 236 if (pool->threads[i] == 0 || !is_thread_alive(pool->threads[i])) 237 { 238 pthread_create(&(pool->threads[i]), NULL, threadpool_thread, (void *)pool); 239 add++; 240 pool->live_thr_num++; 241 printf("new thread -----------------------\n"); 242 } 243 } 244 245 pthread_mutex_unlock(&(pool->lock)); 246 } 247 248 /*销毁多余的线程 忙线程x2 都小于 存活线程,并且存活的大于最小线程数*/ 249 if ((busy_thr_num*2) < live_thr_num && live_thr_num > pool->min_thr_num) 250 { 251 // printf("admin busy --%d--%d----\n", busy_thr_num, live_thr_num); 252 /*一次销毁DEFAULT_THREAD_NUM个线程*/ 253 pthread_mutex_lock(&(pool->lock)); 254 pool->wait_exit_thr_num = DEFAULT_THREAD_NUM; 255 pthread_mutex_unlock(&(pool->lock)); 256 257 for (i=0; i<DEFAULT_THREAD_NUM; i++) 258 { 259 //通知正在处于空闲的线程,自杀 260 pthread_cond_signal(&(pool->queue_not_empty)); 261 printf("admin cler --\n"); 262 } 263 } 264 } 265 266 return NULL; 267 } 268 /*线程是否存活*/ 269 int 270 is_thread_alive(pthread_t tid) 271 { 272 int kill_rc = pthread_kill(tid, 0); //发送0号信号,测试是否存活 273 if (kill_rc == ESRCH) //线程不存在 274 { 275 return false; 276 } 277 return true; 278 } 279 280 /*工作线程*/ 281 void * 282 threadpool_thread(void *threadpool) 283 { 284 threadpool_t *pool = (threadpool_t *)threadpool; 285 threadpool_task_t task; 286 287 while (true) 288 { 289 pthread_mutex_lock(&(pool->lock));//为线程池上锁 290 291 //无任务则阻塞在 任务队列不为空 上,有任务则跳出 292 while ((pool->queue_size == 0) && (!pool->shutdown)) 293 { 294 printf("thread 0x%x is waiting \n", (unsigned int)pthread_self()); 295 pthread_cond_wait(&(pool->queue_not_empty), &(pool->lock)); 296 297 //判断是否需要清除线程,自杀功能 298 if (pool->wait_exit_thr_num > 0) 299 { 300 pool->wait_exit_thr_num--; 301 //判断线程池中的线程数是否大于最小线程数,是则结束当前线程 302 if (pool->live_thr_num > pool->min_thr_num) 303 { 304 printf("thread 0x%x is exiting \n", (unsigned int)pthread_self()); 305 pool->live_thr_num--; 306 pthread_mutex_unlock(&(pool->lock)); 307 pthread_exit(NULL);//结束线程 308 } 309 } 310 } 311 312 //线程池开关状态 313 if (pool->shutdown) //关闭线程池 314 { 315 pthread_mutex_unlock(&(pool->lock)); 316 printf("thread 0x%x is exiting \n", (unsigned int)pthread_self()); 317 pthread_exit(NULL); //线程自己结束自己 318 } 319 320 //否则该线程可以拿出任务 321 task.function = pool->task_queue[pool->queue_front].function; //出队操作 322 task.arg = pool->task_queue[pool->queue_front].arg; 323 324 pool->queue_front = (pool->queue_front + 1) % pool->queue_max_size; //环型结构 325 pool->queue_size--; 326 327 //通知可以添加新任务 328 pthread_cond_broadcast(&(pool->queue_not_full)); 329 330 //释放线程锁 331 pthread_mutex_unlock(&(pool->lock)); 332 333 //执行刚才取出的任务 334 printf("thread 0x%x start working \n", (unsigned int)pthread_self()); 335 pthread_mutex_lock(&(pool->thread_counter)); //锁住忙线程变量 336 pool->busy_thr_num++; 337 pthread_mutex_unlock(&(pool->thread_counter)); 338 339 (*(task.function))(task.arg); //执行任务 340 341 //任务结束处理 342 printf("thread 0x%x end working \n", (unsigned int)pthread_self()); 343 pthread_mutex_lock(&(pool->thread_counter)); 344 pool->busy_thr_num--; 345 pthread_mutex_unlock(&(pool->thread_counter)); 346 } 347 348 pthread_exit(NULL); 349 } 350 351 /*向线程池的任务队列中添加一个任务*/ 352 int 353 threadpool_add_task(threadpool_t *pool, void *(*function)(void *arg), void *arg) 354 { 355 pthread_mutex_lock(&(pool->lock)); 356 357 /*如果队列满了,调用wait阻塞*/ 358 while ((pool->queue_size == pool->queue_max_size) && (!pool->shutdown)) 359 { 360 pthread_cond_wait(&(pool->queue_not_full), &(pool->lock)); 361 } 362 /*如果线程池处于关闭状态*/ 363 if (pool->shutdown) 364 { 365 pthread_mutex_unlock(&(pool->lock)); 366 return -1; 367 } 368 369 /*清空工作线程的回调函数的参数arg*/ 370 if (pool->task_queue[pool->queue_rear].arg != NULL) 371 { 372 free(pool->task_queue[pool->queue_rear].arg); 373 pool->task_queue[pool->queue_rear].arg = NULL; 374 } 375 376 /*添加任务到任务队列*/ 377 pool->task_queue[pool->queue_rear].function = function; 378 pool->task_queue[pool->queue_rear].arg = arg; 379 pool->queue_rear = (pool->queue_rear + 1) % pool->queue_max_size; /* 逻辑环 */ 380 pool->queue_size++; 381 382 /*添加完任务后,队列就不为空了,唤醒线程池中的一个线程*/ 383 pthread_cond_signal(&(pool->queue_not_empty)); 384 pthread_mutex_unlock(&(pool->lock)); 385 386 return 0; 387 }
实例源码二:
1 #include <pthread.h> 2 #include <unistd.h> 3 4 static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER; 5 static pthread_cond_t cond = PTHREAD_COND_INITIALIZER; 6 7 struct node { 8 int n_number; 9 struct node *n_next; 10 } *head = NULL; 11 12 /*[thread_func]*/ 13 static void cleanup_handler(void *arg) 14 { 15 printf("Cleanup handler of second thread./n"); 16 free(arg); 17 (void)pthread_mutex_unlock(&mtx); 18 } 19 static void *thread_func(void *arg) 20 { 21 struct node *p = NULL; 22 23 pthread_cleanup_push(cleanup_handler, p); 24 while (1) { 25 pthread_mutex_lock(&mtx);//这个mutex主要是用来保证pthread_cond_wait的并发性 26 while (head == NULL) {/*这个while要特别说明一下,单个pthread_cond_wait功能很完善,为何这里要有一个while (head == NULL)呢?因为pthread_cond_wait里的线程可能会被意外唤醒,如果这个时候head != NULL,则不是我们想要的情况。这个时候,应该让线程继续进入pthread_cond_wait*/ 27 pthread_cond_wait(&cond, &mtx);/*pthread_cond_wait会先解除之前的pthread_mutex_lock锁定的mtx,然后阻塞在等待对列里休眠,直到再次被唤醒(大多数情况下是等待的条件成立而被唤醒,唤醒后,该进程会先锁定先pthread_mutex_lock(&mtx);,再读取资源*/ 28 //用这个流程是比较清楚的/*block-->unlock-->wait() return-->lock*/ 29 } 30 p = head; 31 head = head->n_next; 32 printf("Got %d from front of queue/n", p->n_number); 33 free(p); 34 pthread_mutex_unlock(&mtx); //临界区数据操作完毕,释放互斥锁 35 } 36 pthread_cleanup_pop(0); 37 return 0; 38 } 39 40 int main(void) 41 { 42 pthread_t tid; 43 int i; 44 struct node *p; 45 pthread_create(&tid, NULL, thread_func, NULL); //子线程会一直等待资源,类似生产者和消费者,但是这里的消费者可以是多个消费者,而不仅仅支持普通的单个消费者,这个模型虽然简单,但是很强大 46 /*[tx6-main]*/ 47 for (i = 0; i < 10; i++) { 48 p = malloc(sizeof(struct node)); 49 p->n_number = i; 50 pthread_mutex_lock(&mtx); //需要操作head这个临界资源,先加锁, 51 p->n_next = head; 52 head = p; 53 pthread_cond_signal(&cond); 54 pthread_mutex_unlock(&mtx); //解锁 55 sleep(1); 56 } 57 printf("thread 1 wanna end the line.So cancel thread 2./n"); 58 pthread_cancel(tid); //关于pthread_cancel,有一点额外的说明,它是从外部终止子线程,子线程会在最近的取消点,退出线程,而在我们的代码里,最近的取消点肯定就是pthread_cond_wait()了。关于取消点的信息,有兴趣可以google,这里不多说了 59 pthread_join(tid, NULL); 60 printf("All done -- exiting/n"); 61 return 0; 62 }