目录
1 线程
1.1 线程控制原语
1.1.1 pthread_self和pthread_create
1.1.2 循环创建多个线程
1.1.3 线程退出
1.1.4 pthread_join函数
1.1.5 获取线程函数的返回值
1.1.6 线程分离
1.1.7 杀死线程
1.1.8 进程和线程控制原语对比
1.2 线程属性
1.2.1 线程属性相关函数
1.2.2 线程的分离状态
1.2.3 线程的栈大小
2 线程同步
2.1 互斥量mutex
2.1.1 死锁
2.1.2 pthread_mutexattr_t
2.2 读写锁
2.2.1 相关函数
2.3 条件变量
2.3.1 相关函数
2.3.2 生产者消费者模型
2.4 信号量——同步
2.4.1 信号量相关函数
3 线程池
3.1 线程池代码
1、线程概念
线程与进程的关系
线程之间的共享和独占资源
优缺点
2、线程控制原语
pthread_self
pthread_create
exit
join
3、线程属性
4、使用线程时的注意事项
线程:LWP(light-weight process) 轻量级的进程,本质仍是进程
线程也具有控制块Thread Control Block
线程是最小的执行(获得时间片即可执行)单位,进程是最小的资源(内存空间,硬件资源等)分配单位——当开启了线程后,CPU分配时间片的单位就变成了线程。此时开了多个线程的进程获得时间片的概率更高,占比更大。
从内核来看进程和线程是一样的,因为内核区分执行程序的方式是PCB,线程和进程有不同的PCB,但是PCB中指向的三级页表是相同的。
PCB中的一个指针,指向一个页表(4KB),页表中存在一条一条的目录项,目录项中也存在一个指针,指针指向二级页表,页表中的目录项的指针指向物理页面。
每一个函数有属于自己的栈帧空间,栈中存放着函数需要的变量。
所以对于线程,它的栈空间是独立的。
使用ps -Lf pid,可以查看一个进程都有哪些线程,LWP表示线程号(CPU分配时间片的依据)。线程ID是进程内区分不同线程的依据。线程号与线程ID不同。
线程资源
1、线程共享资源
(1)文件描述符表
(2)每种信号的处理方式
(3)当前工作目录
(4)用户ID和组ID
(5)内存地址空间
2、线程非共享资源
(1)线程ID
(2)处理器现场(寄存器)和栈指针
(3)独立的栈空间
(4)errno变量
(5)信号屏蔽字
(6)调度优先级
线程优缺点
1、优点
(1)提高程序的并发性
(2)相对于进程,开销小
(3)数据通信、共享数据方便
2、缺点
(1)线程中的函数大多都是库函数,不稳定
(2)调试、编写困难、gdb不支持
(3)对信号支持不好
线程库属于第三方库,在链接时会链接标准C库,但不会主动链接第三方库,所以gcc编译时要加上——" -pthread "选项。
#include
pthread_self——获取线程ID。
pthread_t pthread_self(void); //返回值
pthread_create——创建线程
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine)(void *), void *arg);
成功,返回0;失败,返回错误代码
char *strerror(int errnum); //接受一个错误号,返回错误描述
示例
主线程打印线程ID,进程ID;子线程打印线程ID,进程ID。主线程sleep等待子进程结束。
makefile
执行结果
示例
循环创建5个子线程,并在线程中打印是第几个子线程
执行结果
注意:
画红线部分,使用的是传指针,传指针时使用的值是指针指向的i的值,但是由于线程具有并发性,并不能保证每一条线程都是顺序执行的,且一定比主线程先结束,所以此时获得的i可能已经不是实时的i值了。此时的执行结果如下图所示
void pthread_exit(void *retval); //退出当前线程,在主线程中调用则退出主线程
在主线程中执行pthread_exit退出而不是使用exit或return时(exit和return是退出进程),此时进程会在其他线程执行完后结束
在编写线程时,注意exit,return的使用,尽量使用pthread_exit
阻塞等待线程退出,获取线程退出状态
int pthread_join(pthread_t thread, void **retval); //retval回收pthread_exit的参数
回收多个线程
循环调用pthread_join()函数
pthread_exit(),可以返回线程函数的返回值
pthread_join(),可以获得pthread_exit()的参数
这两个函数配合,即可获得线程的返回值
也可以使用线程创建时的参数来获得线程的返回值??
int pthread_deatch(pthread_t thread); //成功,返回0;失败,返回错误码
线程分离状态:线程主动与主线程断开关系。线程结束后,其退出状态不由其他线程获取,而是直接自己自动释放。
一般情况下,线程终止后,其终止状态一直保留到其他线程调用pthread_join获取它的状态为止。但是线程被置为detach状态后,线程一旦终止就立刻回收它占用的所有资源,而不保留终止状态。不能对一个处于detach状态的线程调用pthread_join。
int pthread_cancel(pthread_t thread); //成功,返回0;失败,返回错误号
杀死线程需要一个取消点(在线程中调用系统调用即可),必须是系统调用——比如系统调用中的create,write等。
如果没有取消点,可以直接在线程中使用pthread_testcancel函数——void pthread_testcancel(void)
进程 | 线程 |
fork | pthread_create |
exit | pthread_exit |
wait | pthread_join |
kill | pthread_cancel |
getpid | pthread_self |
pthread_attr
应先初始化线程属性,再pthread_create创建线程
typedef struct { int etachstate; //线程分离状态 int schedpolicy; //线程调度策略 struct_sched_param schedparam; //线程调度参数 int inheritsched; //线程继承性 int scope; //线程作用域 size_t guardsize; //线程栈末尾的警戒缓冲区大小 int stackaddr_set; //线程的栈设置 void* stackaddr; //线程栈的位置 size_t stacksize; //线程栈的大小 }pthread_attr_t;
初始化线程属性
int pthread_attr_init(pthread_attr_t *attr); //成功,返回0;失败,返回错误码
销毁线程属性所占用的资源
int pthread_attr_destroy(pthread_attr *attr); //成功,返回0;失败,返回错误号
设置线程属性——分离或非分离
int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);
获取线程属性
int pthread_attr_getdetachstate(pthread_attr_t *attr, int *detachstate);
分离状态:PTHREAD_CREATE_DETACHED
加入状态:PTHREAD_CREATE_JOINABLE
如果设置一个线程为分离线程,而这个线程又运行非常快,可以在线程中调用pathread_cond_timedwait函数,让线程等待一会,留出足够的时间让函数pthread_create返回。
当进程栈地址空间不够用时,指定新建线程使用由malloc分配的空间作为自己的栈空间。
int pthread_attr_setstack(pthread_attr_t *attr, void *stackaddr, size_t stacksize); //成功,返回0,;失败,返回错误码
int pthread_attr_getstack(pthread_attr_t *attr, void *stackaddr, size_t *stackszie);
同步
互斥量——pthread_mutex
读写锁——pthread_rwlock
条件变量——pthread_cond;pthread_cond_wait()
信号量——互斥量的升级版
线程同步:一个线程发出某一功能调用时,在没有得到结果之前,该调用不返回。同时其他线程为保证数据一致性,不能调用该功能。
每个线程对资源操作前都尝试先加锁,成功加锁才能操作,操作结束解锁
1、pthread_mutex_init函数,pthread_mutex_destroy函数
#include
int pthread_mutex_destroy(pthread_mutex_t *mutex); //restrict,限制了修改的入口 int pthread_mutex_init(pthread_mutex_t *restrict mutex, //restrict关键字,对该变量进行修改的操作,只能使用该变量操作(其他操作这个指针指向的变量的操作均非法) const pthread_mutexattr_t *restrict attr); //属性的设置可以决定是否用于进程间互斥 pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; //mutex的取值只有1和0,初始化成功值为1
2、pthread_mutex_lock函数,pthread_mutex_trylock函数,pthread_mutex_unlock函数
#include
int pthread_mutex_lock(pthread_mutex_t *mutex); //加锁,mutex-- int pthread_mutex_trylock(pthread_mutex_t *mutex); //锁被占用时不阻塞 int pthread_mutex_unlock(pthread_mutex_t *mutex); //解锁,mutex++
1、线程对同一互斥量加锁两次——阻塞自己导致死锁
2、线程之间的请求的资源被相互占用且不释放自己所占用的资源。线程之间形成一个逻辑上的环
死锁的解决方法
对于第一种,上锁和解锁要一一对应,且不允许嵌套
对于第二种,当无法请求到资源时,放弃自己已经占用的资源
互斥锁属性的设置
pthread_mutexattr_t
int pthread_mutexattr_init(pthread_mutexattr_t *attr);
int pthread_mutexattr_destroy(pthread_mutexattr_t *atr);
int pthread_mutexattr_setpshared(pthread_mutexattr_t *attr, int pshared);
pshared的取值:PTHREAD_PROCESS_PRIVATE(线程锁,进程间私有);PTHREAD_PROCESS_SHARED(进程锁)
读写锁相对于互斥量具有更高的并行性。
特性:写独占,读共享;写锁优先级高
#include
int pthread_rwlock_init(pthread_rwlock_t *restrict rwlock, const pthread_rwlockattr_t *restrict attr); int pthread_rwlock_destroy(pthread_rwlock_t *rwlock); pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER; 1、pthread_rwlock_rdlock函数,pthread_rwlock_tryrdlock函数
#include
int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock); int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock); 2、pthread_rwlock_wrlock函数,pthread_rwlock_trywrlock函数
#include
int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock); int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock); 3、pthread_rwlock_unlock函数
#include
int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);
条件变量本身不是锁,但是它可以造成线程阻塞
条件变量通常与互斥锁配合使用
1、pthread_cond_init函数,pthread_cond_destroy函数
#include
int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr); int pthread_cond_destroy(pthread_cond_t *cond); pthread_cond_t cond= PTHREAD_COND_INITIALIZER; 2、pthread_cond_wait函数,pthread_cond_timedwait函数
(1)pthread_cond_wait
阻塞等待条件变量满足
释放已经掌握的互斥锁
被唤醒后,解除阻塞并重新申请获取互斥锁
(2)pthread_cond_timedwait
阻塞一段时间,在这段时间内尝试上锁
#include
int pthread_cond_timedwait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex, const struct timespec *restrict abstime); int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex); 3、pthread_cond_signal函数,pthread_cond_broadcast
#include
int pthread_cond_broadcast(pthread_cond_t *cond); int pthread_cond_signal(pthread_cond_t *cond);
生产者,消费者,仓库
生产者:仓库未满,生产;仓库满了,阻塞等待
消费者:仓库为空,阻塞等待;仓库非空,消费
消费者:
(1)上锁
(2)检查条件变量是否满足——不满足,则wait会自动解锁
(3)执行消费者行为
(4)解锁
(4)唤醒生产者
生产者:
(1)上锁
(2)检查条件变量是否满足
(3)执行生产者行为
(4)解锁
(5)唤醒被阻塞的消费者
由于互斥锁的粒度比较大,如果我们希望在多个线程间对某一对象的部分数据进行共享,使用互斥锁无法实现,只能将整个对象锁住,使得并发性下降
信号量,进化版的互斥锁(互斥锁mutex = 0 or 1,而信号量是1~N),即信号量表示空闲资源的数量。
1、sem_init函数,sem_destroy函数
#include
//pshared:描述是否可以用于进程间共享 int sem_init(sem_t *sem, int pshared, unsigned int value); int sem_destroy(sem_t *sem); 2、sem_wait函数,sem_trywait函数,sem_timedwait函数
#include
int sem_wait(sem_t *sem); //如果信号量大于0,则执行“ -- ”;等于0,则阻塞 int sem_trywait(sem_t *sem); int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout); 3、sem_post函数
#include
int sem_post(sem_t *sem); //信号量++,同时唤醒阻塞在信号量上的线程
来了一个事件,放入任何队列
线程从任务队列中取任务进行处理——无任务时,线程阻塞
这里类似生产者,消费者模型
线程池有一个基数,当任务超过基数时,扩大线程池容量,所以需要设置要给最小线程数,最大线程数,扩容步长
1、如何创建线程池——创建好线程后,由于没有任务,要把线程阻塞(条件变量)。线程的创建需要处理函数,而实际的任务是多样性的,多以任务本身并不是创建线程所使用的函数,而是在线程中调用任务函数。相当于加上了一层包装,包装使得内部透明,不知细节。
2、如何向线程池中添加任务——
3、参数如何传递到线程中——一个全局变量即可完成参数的共享,即创建一个全局任务队列,队列中存放着任务以及参数。通过传指针的方式便可以访问该全局变量,当然对于共享变量,要上锁。
4、
#include
#include #include #include #include #include #include #include #include #include "threadpool.h" #define DEFAULT_TIME 10 /*10s检测一次*/ #define MIN_WAIT_TASK_NUM 10 /*如果队列 > MIN_WAIT_TASK_NUM,则扩容线程池*/ #define DEFAULT_THREAD_VARY 10 /*每次创建和销毁的线程个数*/ #define true 1 #define false 0 typedef struct { void *(*function)(void*); /*函数指针,回调函数*/ void *arg; /*回调函数参数*/ }threadpool_task_t; /*各子线程任务结构体*/ struct threadpool_t { pthread_mutex_t lock; /*用于锁住本结构体*/ pthread_mutex_t thread_counter; /*记录忙状态线程个数的锁*/ pthread_cond_t queue_not_full; /*当任务队列满时,添加任务的线程阻塞,等待此条件变量*/ pthread_cond_t queue_not_empty; /*任务队列不为空时,通知等待任务的线程*/ pthread_t *threads; /*存放线程池中每个线程的tid*/ pthread_t adjust_tid; /*存管理线程的tid*/ threadpool_task_t *task_queue; /*任务队列*/ int min_thr_num; /*线程池最小线程数*/ int max_thr_num; /*线程池最大线程数*/ int live_thr_num; /*当前存活线程个数*/ int busy_thr_num; /*忙状态线程个数*/ int wait_exit_thr_num; /*要销毁的线程个数*/ int queue_front; /*task_queue队头下标*/ int queue_rear; /*task_queue队尾下标*/ int queue_size; /*task_queue队中实际任务数*/ int queue_max_size; /*task_queue队列中可容纳任务数上限*/ int shutdown; /*标志位,线程池使用状态,true或false*/ }; //+++++++++++++++++++++++++++++++++++++++++++++++++// /*--------------------管理者线程--------------------*/ //+++++++++++++++++++++++++++++++++++++++++++++++++// //扩容,缩容 void *adjust_thread(void *) { int i; threadpool_t *pool = (threadpool_t *)threadpool; while (!pool->shutdown) { sleep(DEFAULT_TIME); /*对线程池进行周期性管理*/ pthread_mutex_lock(&(pool->lock)); int queue_size = pool->queue_size; /*任务数*/ int live_thr_num = pool->live_thr_num; /*存活线程数*/ pthread_mutex_unlock(&(pool->lock)); pthread_mutex_lock(&(pool->thread_counter)); int busy_thr_num = pool->busy_thr_num; /*忙线程数*/ pthread_mutex_unlock(&(pool->thread_counter)); /*创建新线程算法:任务数大于最小线程个数,且存活的线程数少于最大线程个数*/ if (queue_size >= MIN_WAIT_TASK_NUM && live_thr_num < pool->max_thr_num) { pthread_mutex_lock(&(pool->lock)); int add = 0; /*一次增加 DEFAULT_THREAD 个线程*/ for (int i = 0; i < pool->max_thr_num && add < DRFAULT_THREAD_VARY && pool->live_thr_num < pool->max_thr_num; ++i) { if (pool->threads[i] == 0 || !is_thread_alive(pool->threads[i])) { pthread_create(&(pool->threads[i]), NULL, threadpool_thread, (void*)pool); add++; pthread_mutex_unlock(&(pool->lock)); } } pthread_mutex_unlock(&(pool->lock)); } /*销毁多余的空闲线程算法:忙线程 * 2 < 存活的线程数,且 存活的线程数 > 最小线程数*/ if (busy_thr_num * 2 < live_thr_num && live_thr_num > pool->min_thr_num) { /*一次销毁 DEFAULT_THREAD 个线程*/ //这个本身合理吗?? pthread_mutex_lock(&(pool->lock)); pool->wait_exit_thr_num = DEFAULT_THREAD_VARY; pthread_mutex_unlock(&(pool->lock)); for (i = 0; i < DEFAULT_THREAD_VARY; i++) // { /*尽管现在队列是空的,但依然发一个通知过去,让空闲线程不再阻塞,自动结束*/ /*通知处在空闲状态的线程,它们会自行终止*/ pthread_cond_signal(&(pool->queue_not_empty)); } } } return NULL; } //+++++++++++++++++++++++++++++++++++++++++++++++++// /*--------------------工作线程----------------------*/ //+++++++++++++++++++++++++++++++++++++++++++++++++// void *threadpool_thread(void *threadpool) { threadpool_t *pool = (threadpool_t *)threadpool; threadpool_task_t task; while (true) { /*所以,没有任务的线程本身是阻塞的,参数如何传递进来呢?只要一个全局参数,就可以传递进来了*/ /*如果有一个全局任务队列,任务都放在队列里,所有线程都可以访问该队列,就达到了目的*/ /*刚创建出线程,等待任务队列里有任务,否则阻塞等待任务队列里有任务后再唤醒接受任务*/ pthread_mutex_lock(&(pool->lock)); //锁住整个pool /*当任务队列为空,且线程池开启——让空闲线程自动终止*/ while ((pool->queue_size == 0) && (!pool->shutdown)) { printf("thread 0x%x is waiting\n", (unsigned int)pthread_self()); /*条件变量,等待任务队列不为空——当任务队列不为空时,发信号给阻塞线程*/ pthread_cond_wait(&(pool->queue_not_empty), &(pool->lock)); /*清除指定数目的空闲线程,如果要结束的线程个数大于0,结束线程*/ /*让空闲线程主动终止*/ if (pool->wait_exit_thr_num > 0) { pool->wait_exit_thr_num--; /*如果线程池里线程个数大于最小值时,可以结束当前线程*/ if (pool->live_thr_num > pool->min_thr_num) { printf("thread 0x%x is exiting\n", (unsigned int)pthread_self()); pool->live_thr_num--; pthread_mutex_unlock(&(pool->lock)); pthread_exit(NULL); } } } /*关闭线程池,退出每一个线程*/ if (pool->shutdown) { pthread_mutex_unlock(&(pool->lock)); printf("thread 0X%X is exitiing\n", (unsigned int)pthread_self()); pthread_exit(NULL); } /*从任务队列中获取任务*/ task.function = pool->task_queue[pool->queue_front].function; task.arg = pool->task_queue[pool->queue_front].arg; pool->queue_front = (pool->queue_front + 1) % pool->queue_max_size; pool->queue_size--; /*通知可以有新的任务添加进来*/ pthread_cond_broadcast(&(pool->queue_not_full)); /*任务取出后,立即将线程池锁释放*/ pthread_mutex_unlock(&(pool->lock)); /*执行任务*/ printf("thread ox%x start working\n", (unsigned int)pthread_self()); pthread_mutex_lock(&(pool->thread_counter)); /*忙状态线程数变量锁*/ pool->busy_thr_num++; pthread_mutex_unlock(&(pool->thread_counter)); (*(task.function))(task.arg); //执行回调函数 /*任务结束处理*/ printf("thread 0x%x end working\n", (unsigned int)pthread_self()); pthread_mutex_lock(&(pool->thread_counter)); pool->busy_thr_num--; /*忙线程状态数-1*/ pthread_mutex_unlock(&(pool->thread_counter)); } pthread_eixt(NULL); } //+++++++++++++++++++++++++++++++++++++++++++++++++// /*----------------向队列添加任务------------------*/ //+++++++++++++++++++++++++++++++++++++++++++++++++// int threadpool_add(threadpool_t *pool, void*(*function)(void *arg), void *arg) { pthread_mutex_lock(&(pool->lock)); //锁住pool /*队列满了,调用wait阻塞*/ while ((pool->queue_size == pool->queue_max_size) && (!pool->shutdown)) { pthread_cond_wait(&(pool->queue_not_full), &(pool->lock)); } if (pool->shutdown) { pthread_mutex_unlock(&(pool->lock)); } /*清空工作线程调用的回调函数的参数arg*/ /*为什么要清空队尾的数据*/ /*队尾指针是指向空数据的*/ if (pool->task_queue[pool->queue_rear].arg != NULL) { free(poll->task_queue[pool->queue_rear].arg); pool->task_queue[pool->queue_rear].arg = NULL; } /*添加任务到任务队列里*/ pool->task_queue[pool->queue_rear].function = function; pool->task_queue[pool->queue_rear].arg = arg; pool->queue_rear = (pool->queue_rear + 1) % pool->queue_max_size; /*环形队列,队尾指向空元素*/ pool->queue_size++; /*添加完任务,队列不为空,唤醒线程池,等待处理任务的线程*/ pthread_cond_signal(&(pool->queue_not_empty)); pthread_mutex_unlock(&(pool->lock)); return 0; } //+++++++++++++++++++++++++++++++++++++++++++++++++// /*--------------------创建线程池--------------------*/ //+++++++++++++++++++++++++++++++++++++++++++++++++// threadpool_t *threadpool_create(int min_thr_num, int max_thr_num, int queue_max_size) { int i; threadpool_t *pool = NULL; do { if ((pool = (threadpool_t *)malloc(sizeof(threadpool_t))) == NULL) { printf("malloc threadpool fail\n"); break; } pool->min_thr_num = min_thr_num; pool->max_thr_num = max_thr_num; pool->busy_thr_num = 0; pool->live_thr_num = min_thr_num; /*初始时,活着的线程数*/ pool->queue_size = 0; /*初始时,有0个任务*/ pool->queue_max_size = queue_max_size; pool->queue_front = 0; pool->queue_rear = 0; pool->shutdown = false; /*初始时,不关闭线程池*/ /*根据最大线程上限数,给工作线程数组开辟空间,并清零*/ /*一个存储线程标识的数组*/ pool->threads = (pthread_t *)malloc(sizeof(pthread_t) * max_thr_num); if (pool->threads = NULL) { printf("malloc threads fail\n"); break; } memset(pool->threads, 0, sizeof(pthread_t) * max_thr_num); /*队列开辟空间*/ pool->task_queue = (threadpool_task_t *)malloc(sizeof(threadpool_task_t) * queue_max_size); if (pool->task_queue == NULL) { printf("malloc task_queue fail\n"); break; } /*初始化互斥锁,条件变量*/ if (pthread_mutex_init(&(pool->lock), NULL) != 0 || pthread_mutex_init(&(pool->thread_counter), NULL) != 0 || pthread_cond_init(&(pool->queue_not_empty), NULL) != 0 || pthread_cond_init(&(pool->queue_not_full), NULL) != 0) { printf("init the lock or cond fail\n"); break; } /*启动min_thr_num个work thread*/ /*创建了多个线程,线程函数是threadpool_thread*/ for (i = 0; i < min_thr_num; ++i) { pthread_create(&(pool->threads[i]), NULL, threadpool_thread, (void*)pool); /*threadpool_thread,线程回调函数*/ prinf("start thread 0x%x...\n", (unsigned int)pool->threads[i]); } /*启动管理者线程*/ pthread_create(&(pool->adjust_tid), NULL, adjust_thread, (void *)pool); /*启动管理者线程*/ return pool; }while(0); threadpool_free(pool); /*如果创建失败,则释放已经分配的内存*/ } //+++++++++++++++++++++++++++++++++++++++++++++++++// /*--------------------释放线程池空间----------------*/ //+++++++++++++++++++++++++++++++++++++++++++++++++// int threadpool_free(threadpool_t *pool) { if (pool == NULL) { return -1; } if (pool->task_queue) { free(pool->task_queue); } if (pool->threads) { free(pool->threads); pthread_mutex_lock(&(pool->lock)); pthread_mutex_destroy(&(pool->lock)); pthread_mutex_lock(&(pool->thread_counter)); pthread_mutex_destroy(&(pool->thread_counter)); pthread_cond_destroy(&(pool->queue_not_empty)); pthread_cond_destroy(&(pool->queue_not_full)); } free(pool); pool = NULL; return 0; } //+++++++++++++++++++++++++++++++++++++++++++++++++// /*--------------------销毁线程池--------------------*/ //+++++++++++++++++++++++++++++++++++++++++++++++++// int threadpool_destroy(threadpool_t *pool) { int i = 0; if (pool == NULL) { return -1; } pool->shutdown = true; /*先销毁管理线程*/ pthread_join(pool->adjust_tid, NULL); for (i = 0; i < pool->live_thr_num; ++i) { /*通知所有空闲线程*/ pthread_cond_broadcast(&(pool->queue_not_empty)); } for (i = 0; i < pool->live_thr_num; ++i) { pthread_join(pool->thread[i], NULL); //等所有线程结束后,在结束销毁线程 } threadpool_free(pool); return 0; } //+++++++++++++++++++++++++++++++++++++++++++++++++// /*---------------判断线程是否存活-------------------*/ //+++++++++++++++++++++++++++++++++++++++++++++++++// int is_thread_alive(pthread_t tid) { int kill_rc = pthread_kill(tid, 0); //发送0信号,测试线程是否存活 if (kill_rc == ESRCH) { return false; } return true; }