线程池的使用方法
线程池的具体实现:
线程池本质上是一个结构体描述的数据结构体
typedef struct pthread_pool
{
//线程池的实现可能会按照项目的不同也会有所不同 但是大体上应该要有如下成员
struct task * task_list; //任务队列(链表) 执行第一个要执行的任务 所有的线程都从这个任务链表中获取任务
pthread_mutex_t lock ; //因为“任务队列”是一种共享资源 所以需要互斥访问 以避免出问题 所以需要线程互斥锁
pthread_cond_t cond; //当我们的“任务队列”中没有人物的时候 线程池内的线程都要休眠
//以避免资源的浪费 所以需要线程条件变量
//线程条件变量用来表示“任务队列”中是否有任务。
pthread_t *tids ; //指向线程ID的数组 用来保存线程池中所有线程的ID
unsigned int active_threads;//线程池正在服役的线程数 ---》线程的个数
unsigned int max_waiting_tasks; //线程池任务队列最大的任务数量
unsigned int cur_waiting_tasks;//线程池任务队列当前的任务数量
bool shutdowm ;//表示是否退出程序
//按需增加
}pthread_pool;
//任务队列(链表) 线程池中的线程会不断地从任务队列中获取任务去执行
//任务队列的链表结点
struct task
{
//每一个结点保存一个任务,所谓任务实际上就是把一个文件或目录从源目录拷贝到目标目录下
//那么这个任务该怎么保存?
//任务的完成是通过函数来实现 所以我们如果要保存一个任务的话
//只需要保存完成任务的函数(cp_file)的地址就可以了(函数指针)
//也就是说 我们要去完成这个任务 就是去结点保存的地址上去执行一个函数就可以了
//函数只要执行完了 任务也就完成了
//那么我们需要定义一个函数指针 保存任务函数的地址
void *(* do_task)(void * arg);
void * arg; //我们需要给任务函数传递参数(文件名)
struct task * next;//执行下一个结点(任务)的指针。
};
线程池代码的具体实现:
/*
init_pool: 线程池初始化函数
函数功能: 初始化指定的线程池 线程池中有thread_num个初始化线程
参数列表:
@pool: 指定 指向你要初始化的线程池
@thread_num:你要初始化的线程池中一开始的线程数量
返回值:
成功返回0
失败返回-1
*/
int init_pool(pthread_pool* pool , unsigned int thread_num)
{
//初始化线程池结构体
//初始化线程互斥锁
//初始化线程条件变量
//创建thread_num个线程 同时记录所有线程的id 让所有线程按照”任务调度函数“的调度去执行任务
}
/*
routine: 任务调度函数(线程函数) 所有的线程开始都要执行此函数
此函数不停地从线程池的任务队列中取任务然后去执行
参数列表:
@arg: arg表示的是线程池的指针 。在线程池中有任务队列 任务队列中有任务节点
每一个任务结点都包含了函数指针和函数参数
(arg要让你能够找到那个任务)
返回值:
无
*/
void * routine(void * arg)
{
//因为这个函数需要访问任务队列 任务队列是共享资源 需要上锁和解锁
//获取线程互斥锁 上锁
while(当条件不满足的时候(任务队列中没有任务的))
{
//当前进程休眠
}
//当条件满足的时候 将任务结点从任务链表中取下来
//获取线程互斥锁 解锁
//按照任务结点中的任务去执行任务(去执行cp_file)
//释放任务结点(free)
}
/*
destroy_pool : 销毁线程池 要先保证所有的任务都已经完成了。
...
*/
int destroy_pool(pthread_pool * pool)
{
//释放所有空间 ,等待任务执行完毕
//唤醒所有的线程
//利用pthread_join凹函数回收每一个线程
}
/*
add_task: 给任务队列增加任务: 把do_task指向的任务(函数指针)和arg指向的参数 保存到一个结构体中去
同时将任务节点添加到pool表示的线程池的任务队列中去。
参数列表:
@pool : 指针 表示你要添加任务的线程池
@fun_task : 你要添加的任务(cp_file )
@fun_arg : 你要执行任务的参数(两个文件名)
返回值:
成功返回0
失败返回-1
*/
int add_task(pthread_pool * pool , void *(*fun_task)(void * arg) , void * fun_arg )
{
//需要把第二个参数和第三个参数 封装成 任务队列的节点类型(struct task 类型 )
//把这个节点添加到任务队列中去 (注意上锁和解锁)
//在假如任务之后 要唤醒其他等待的线程
}
//往线程池中添加线程
int add_threads(pthread_pool* pool , unsigned int add_threads_num);
//删除线程池中的线程
int remove_threads(pthread_pool* pool , unsigned int remove_threads_num);
void pthread_cleanup_push(void (*routine)(void *),void *arg);
pthread_cleanup_push用来设置一个线程退出清理函数。
当线程退出(意外)的时候会自动执行我指定的清理函数(一般防止带锁退出)
只能用在线程中
void pthread_cleanup_pop(int execute);
取消一个线程退出清理函数