系统编程之线程池
在进程中,创建多个线程,每当有任务执行时,直接调用已创建好的线程执行,不需要额外创建线程。
实际情况是线程的数量受限于计算机内存不能创建太多,那么就可以利用线程池设置线程数量上限
那么如何设计这个任务工作链表?
单项不循环链表
struct task_list{
route *fuc;//线程执行任务函数指针,该指针指向返回值void*,参数为void*的函数
void *arg//线程执行任务函数的参数
struct task_list *next;
};
结构体成员是函数怎么定义?
自定义一个函数类型
typedef void *(route)(void *);
//定义了一个route为返回值void*,参数为void*的函数
如何设计线程池?
为避免多个线程争抢同一个任务,使用互斥锁
为让线程池中等待的线程知道有任务需要他们,使用条件变量通知等待的线程
struct pthread_pool{
pthread_mutex_t m;//互斥锁
pthread_cond_t v;//条件变量
struct task_list *list;//任务工作链表,
//malloc分配内存空间后,用于保存链表头部
pthread_t *tid;//线程数组
//malloc分配内存空间后,再确定数组大小;
unsigned int active_pthread;//正在运行的子线程个数
unsigned int wait_pthread;//正在等待子线程个数
bool shutdown;//退出线程池的标志位
};
=====================================================
使用 命令 grep -r “关键字” 路径 可以查找该目录下包含该关键字的所有文件
=====================================================
任务:使用线程池实现一个简单的计时。
/********************************************************************
> File Name: pthread_pool.c
> Author: xiening
> Mail: 1606598696@qq.com
> Created Time: 2020年09月07日 星期一 22时14分24秒
*******************************************************************/
#include "pthread_pool.h"
//记时函数
void *time_delay()
{
int t = 0;
while(1)
{
printf("sec:%d\n", t);
sleep(1);
t++;
}
pthread_exit(NULL);
}
//线程执行函数
void *func(int t)
{
printf("pid=%#x begin\n", (int)pthread_self());
sleep(t);
printf("pid=%#x end\n", (int)pthread_self());
// pthread_exit(NULL);
return NULL;
}
//线程池初始化,初始化结构体内的成员
void pthread_init(struct pthread_pool *pool)
{
pthread_mutex_init(&pool->m, NULL);
pthread_cond_init(&pool->v, NULL);
//创建任务链表的头节点,下一个指向空表示没有任何任务
pool->list = malloc(sizeof(struct task_list));
if(pool->list == NULL)
exit(0);
pool->list->next = NULL;
//确定子线程最大个数
pool->tid = malloc(sizeof(pthread_t)*pthread_MAX);
if(pool->tid == NULL)
{
perror("malloc tid error");
exit(0);
}
//当前没有一个线程被创建且尚未有任务
pool->active_pthread = 0;
pool->wait_task = 0;
pool->shutdown = false;
}
//解除死锁函数
void handler(void *arg)
{
struct pthread_pool *pool = (struct pthread_pool *)arg;
pthread_mutex_unlock(&pool->m);
}
//线程执行函数
void *pthread_f(void *arg)
{
struct pthread_pool *pool = (struct pthread_pool *)arg;
printf("pthread = %#x begin\n", (int)pthread_self());
//加锁前设置注册解除死锁退出函数
pthread_cleanup_push(handler, (void *)pool);
while(1)
{
//获取锁资源
pthread_mutex_lock(&pool->m);
//检查任务链表是否为空
//如果为空则进入等待,如果不为空则执行
while(pool->list->next == NULL && !pool->shutdown )
{
pthread_cond_wait(&pool->v, &pool->m);
}
//退出标志位为真时,当还有任务仍然继续执行
if(pool->shutdown && pool->list->next == NULL)
{
printf("shutdown为真,任务为空\n");
pthread_mutex_unlock(&pool->m);
break;
}
//获取被执行的任务,被将该任务从节点中删除
struct task_list *node;
node = pool->list->next;
pool->list->next = node->next;
pool->wait_task--;
//释放锁
pthread_mutex_unlock(&pool->m);
//设置当前线程在执行任务函数时不可取消
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
//执行函数
node->fuc(node->arg);
free(node);
//执行完后可以取消
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
}
//删除注册死锁解除函数
pthread_cleanup_pop(0);
return NULL;
}
//申请创建子线程,在线程池中增加num个子线程
void pthread_pool_add(struct pthread_pool *pool, unsigned int num)
{
if(pool->active_pthread + num > pthread_MAX)
{
printf("pthread_pool is full\n");
return;
}
int i = 0;
int ret = 0;
int pthread_num = 0;
for(i=pool->active_pthread; i<pool->active_pthread+num; i++)
{
ret = pthread_create(&pool->tid[i], NULL, pthread_f, (void*)pool);
if(ret != 0)
{
perror("pthread_create error");
break;
}
//创建成功一个线程就加一
pthread_num++;
}
pool->active_pthread += pthread_num;
}
//向任务链表中添加任务
void task_add(struct pthread_pool *pool, route *fuction, int t)
{
if(pool->wait_task >= task_MAX)
{
printf("task add is full\n");
return;
}
struct task_list *new = malloc(sizeof(struct task_list));
if(new == NULL)
{
perror("malloc struct task_list error");
exit(0);
}
new->fuc = fuction;
new->arg = t;
new->next = NULL;
//把新节点加入到链表末尾
struct task_list *p = pool->list;
while(p->next != NULL)
{
p = p->next;
}
p->next = new;
pool->wait_task++;
//唤醒条件变量阻塞的线程
pthread_cond_signal(&pool->v);
}
//退出线程池
void destory_pool(struct pthread_pool *pool)
{
//把标志位设为ture
pool->shutdown = true;
//向所有正在等待的条件变量的线程发送
pthread_cond_broadcast(&pool->v);
//等待所有线程结束,自动结束
int i = 0;
for(i=0; i<pool->active_pthread; i++)
{
pthread_join(pool->tid[i], NULL);
}
printf("线程池全部退出\n");
//释放申请的堆内存
free(pool->list);
free(pool->tid);
}
int main(int argc, char const *argv[])
{
//计时线程
pthread_t tid;
pthread_create(&tid, NULL, time_delay, NULL);
/*
pthread_join(tid1, NULL);
pthread_join(tid2, NULL);
*/
//线程池初始化
struct pthread_pool pool;
pthread_init(&pool);
//向线程池添加2个线程
pthread_pool_add(&pool, 2);
sleep(5);
//添加任务
task_add(&pool, func, 5);
task_add(&pool, func, 7);
task_add(&pool, func, 10);
task_add(&pool, func, 6);
//自动退出线程池
destory_pool(&pool);
pthread_cancel(tid);
return 0 ;
}