线程:
为什么需要线程池? thread_pool
应用程序创建对象,然后又销毁对象很消耗资源的。
如果我们搞一个程序 去复制一个目录:(有10000个文件)
找到一个文件名,创建一个线程去做复制文件的工作。
因此:预先创建有限数量的线程。加入先创建20个线程, 另外一方面,去搜索目录,找到文件名:把要复制的文件的任 务挂到任务队列上
线程:不停的去看 有没有还未完成的任务
有:就去完成任务
没有: 休息,等通知
于是:一些“池化资源”技术就产生了
主进程:main 要做的事情
1. 初始化一个线程池
init_pool(thread_pool *pool, unsigned int threads_num);
thread_pool : 自定义的一个 描述线程池的 数据结构(结构体)
threads_num: 初始化 要干活的线程数,这些线程都是做同样的工作
线程的工作: 取任务,完成任务
2. 添加任务 : 把 do_task函数,arg 参数, 添加到链表中去
add_task(pool,do_task,(void *)arg);
将任务 do_task 挂到一个任务队列中去,并且通知线程
pthread_cond_signal
3. 销毁线程池
destroy_pool(thread_pool *pool);
通知干活的线程 可以退出了(公司注销),------>设置一个标志: shutdown =1
等待干活的线程回来
销毁一些资源:锁,条件变量
================================线程 ==================================
线程怎么干活? 其实就是考虑 pthread_create的 第三个参数 arg 该怎么写
假设我们对这个函数取名叫做:routine
while(1)
{
while( 没有新任务 && 系统还未退出shutdown==0)
休息,等通知 pthread_cond_wait(&cond, &lock)
if( 没有新任务 && shutdown==1)
准备撤(线程退出) pthread_exit
if( 有新任务) 执行新任务
(): 取任务,完成任务
}
若干个任务怎么去描述?===》任务队列: 链表
到底任务要什么事情?
当前,什么事情都可以做,把要做的事情定义到 函数里面,传给 do_task
我们的例子:把任务安排成:复制文件
显示我们的任务里面需要传参数: 源文件 目的文件 fd
//任务节点:链表
struct task
{
void *(*do_task)(void *arg); //函数指针,指向任务要执行的函数
void *arg;// 传给do_task的参数
struct task *next;
};
===================================pool==================================
我们可以定义一个结构体: thread_pool
为什么设置一个池子? 控制任务的数量不能太多,不能涌入太多的任务。
设置线程的数量,控制这些任务不能同时运行。
定义一个常量:MAX_WAITING_TASK 表示纪录当前正在等待的任务数。
在 pool 结构中定义一个 active_threads 来记录当前到底又几个线程在干活。
任务队列 task_list 链表, 是很重要的公共资源(添加任务,取任 务),父进程和干活的线程都要访问它,所有要对它进行保护。 互斥锁 +条件变量
bool init_pool(thread_pool *pool, unsigned int threads_num)
{
//初始化lock,cond
shutdown = 0;
waiting_tasks = 0;
active_threads = threads_num;
初始化 task_list
tids = (pthread_t *)malloc(threads_num*sizeof(pthread_t));
创建 active_threads 个线程
}
================================条件变量 cond==============================
在线程的 routine 函数中,在某些情况下,线程会进入休眠状态。 需要等待某个条件出来再唤醒它。 谁来唤醒它?
1. 父进程退出=======> destroy_pool :
唤醒所有线程
2. 来了任务 =======> add_task
唤醒一个等在 cond 条件变量上的线程
pthread_cond_signal
===================================互斥锁 lock =============================
需要包含对象: pool->waiting_tasks , pool->task_list
怎么判别要不要包含? 公共的变量可能存在并发的情况下,在我们的项目中:需要加锁的函数:
routine , add_task
=====================================main================================
我们的项目就是实现: cp 源文件 目的文件
为了体现多线程,我们允许原文件和目的文件是目录
步骤:
1. 调用 pool_init初始化线程池
2. 怎么去构造 N个任务,其中每个任务仅仅是 copy srcf detf
难点: 实现 copydir 函数
copydir
{
遍历 src 目录下的所有文件(普通文件 ,目录文件)
如果是普通文件: copyfile
如果是目录文件: copydir
}
3. 销毁线程池