系统编程学习日记---线程池、

一、分析线程池工程文件

pool_test/

      main.c    (使用线程池做的小案例)                  ------>需要修改,你想需要线程池干什么事,修改即可

      thread_pool.c     (线程池中函数接口源码)      -------不需要修改,直接拿过去用

      thread_pool.h      (线程池头文件)     --------不需要修改,直接拿过去

 

线程池接口设计书.doc   -->说明线程池中函数接口的用法

                                       ----->具体这些函数的使用方法在thread_pool.c

  二、分析线程池模型”

1.什么是线程池,  

线程池就是多个线程组合起来的一个集合。

2.如何表示线程池:

使用一个结构体来描述    ---------- thread_pool.h

thread_pool.h

#ifndef _THREAD_POOL_H_
#define _THREAD_POOL_H_

#include <stdio.h>
#include <stdbool.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>

#include <errno.h>
#include <pthread.h>

#define MAX_WAITING_TASKS	1000
#define MAX_ACTIVE_THREADS	20

struct task
{
	void *(*do_task)(void *arg);//任务函数
	void *arg;               //传递给任务函数的参数

	struct task *next;         //指向下一个任务叠构提的指针你
};

typedef struct thread_pool
{
	pthread_mutex_t lock;  //互斥锁
	pthread_cond_t  cond;   //条件变量
	bool shutdown;          //当前系统的标志位,true---线程池处于关闭状态,flase----线程池处于开启状态      
	struct task *task_list;  //指向任务队列头节点的指针,每一个任务节点都包含的任务函数,执行完这个函数任务就完成了。
	pthread_t *tids;         //存储线程ID号的空间
	unsigned max_waiting_tasks;    //线程池中最大等待任务个数
	unsigned waiting_tasks;        //当前正在等待任务的个数
	unsigned active_threads;      //当前线程池中线程的个数
}thread_pool;
//任务函数


bool init_pool(thread_pool *pool, unsigned int threads_number);
bool add_task(thread_pool *pool, void *(*do_task)(void *arg), void *task);
int  add_thread(thread_pool *pool, unsigned int additional_threads_number);
int  remove_thread(thread_pool *pool, unsigned int removing_threads_number);
bool destroy_pool(thread_pool *pool);

void *routine(void *arg);


#endif

 

 

二、线程池中的函数接口:

1,线程池初始化:init_pool( )

原型

bool init_pool(thread_pool * pool,

             unsigned int  threads_number);

功能描述

创建一个新的线程池,包含threads_number个活跃线程

参数

pool: 线程池指针

threads_number: 初始活跃线程个数(大于等于1)

返回值

成功返回true,失败返回false

所在头文件

thread_pool.h

备注

线程池最少线程个数为1

 

2,投送任务:add_task( )

原型

bool add_task(thread_pool *pool,

              void *(*do_task)(void *arg),

              void * arg);

功能描述

往线程池投送任务

参数

pool: 线程池指针

do_task: 投送至线程池的执行例程

arg: 执行例程do_task的参数,若该执行例程不需要参数可设置为NULL

返回值

成功返回true,失败返回false

所在头文件

thread_pool.h

备注

任务队列中最大任务个数为MAX_WAITING_TASKS

 

 

3,增加活跃线程:add_thread( )

原型

int add_thread(thread_pool *pool,

               unsigned int additional_threads);

功能描述

增加线程池中活跃线程的个数

参数

pool: 需要增加线程的线程池指针

additional_threads: 新增线程个数

返回值

>0: 实际新增线程个数

-1: 失败

所在头文件

thread_pool.h

备注

 

4,删除活跃线程:remove_thread( )

原型

int remove_thread(thread_pool *pool,

                  unsigned int removing_threads,);

功能描述

删除线程池中活跃线程的个数

参数

pool: 需要删除线程的线程池指针

removing_threads: 要删除的线程个数。该参数设置为0时直接返回当前线程池线程总数,对线程池不造成任何其它影响

返回值

>0: 当前线程池剩余线程个数

-1: 失败

所在头文件

thread_pool.h

备注

1,线程池至少存在1条活跃线程

2,如果被删除的线程正在执行任务,则将等待其完成任务之后删除

 

5,销毁线程池:destroy_pool( )

原型

bool destroy_pool(thread_pool *pool,);

功能描述

阻塞等待所有任务完成,然后立即销毁整个线程池,释放所有资源和内存

参数

pool: 将要销毁的线程池

返回值

成功返回true,失败返回false

所在头文件

thread_pool.h

备注

 

thread_pool.c

#include "thread_pool.h"

//线程取消例程函数
void handler(void *arg)
{
	//1. 输出一下我自己的TID号,告诉大家,我要结束了!
	printf("[%u] is ended.\n",
		(unsigned)pthread_self());

	//2. 线程要退出,可以,但是要先解锁。
	pthread_mutex_unlock((pthread_mutex_t *)arg);
}

void *routine(void *arg)
{
	//1. 线程先接住线程池变量的地址
	thread_pool *pool = (thread_pool *)arg;
	struct task *p;

	while(1)
	{
		//2. 设置线程取消例程函数
		pthread_cleanup_push(handler, (void *)&pool->lock);
		
		//3. 上锁。
		pthread_mutex_lock(&pool->lock);
		
		//4. 当线程池中等待的任务个数为0,并且线程池为开启状态时
		//跳出循环的条件:
		//1>. 等待任务个数>0
		//2>. 线程池的shutdown为true
		//1>和2>同时为假,也会跳出循环。
		while(pool->waiting_tasks == 0 && !pool->shutdown)
		{
			//5. 进入条件变量中等待。
			pthread_cond_wait(&pool->cond, &pool->lock); 
		}

		//如果当前的任务个数=0 并且 线程池为关闭状态,线程才会退出。
		if(pool->waiting_tasks == 0 && pool->shutdown == true)
		{	
			//解锁
			pthread_mutex_unlock(&pool->lock);	
			
			//走人
			pthread_exit(NULL); 
		}

		//1>. 什么时候,线程会从条件变量中出来?
		//第一种情况,当投放任务,随机唤醒一个线程,线程因为"pool->waiting_tasks == 0"为假,就会跳出来。
		//第二种情况:因为线程池为关闭状态,导致这个条件"!pool->shutdown"为假而跳出循环。
		//第三种情况:又有任务做,线程池又关闭,也会跳出来。
		
		//2>. 什么情况下,线程才会退出。
		//只有任务队列中没有任务做,并且线程池为关闭状态,线程才会退出。
		
		//3>. 以下的情况,线程都不会退出。
		//1> 有任务,  线程池是关闭状态,那么线程就会做完所有的任务之后,再退出。
		//2> 有任务,  线程池是开启状态,那么线程就会做完所有的任务之后,去条件变量中睡眠。
		//3. 没有任务,线程池为开启状态  -> 这种情况,线程不会从条件变量中醒来。
		//4. 没有任务,线程池为关闭状态  -> 线程退出。
		
		//让p指向头节点的下一个节点。
		p = pool->task_list->next;
		
		//让头节点的指针域指向p的下一个节点。
		pool->task_list->next = p->next;
		
		//当前等待的任务个数-1
		pool->waiting_tasks--;

		//解锁。
		pthread_mutex_unlock(&pool->lock);
		
		//删除线程取消例程函数。
		pthread_cleanup_pop(0);
		
		//设置线程当前不能响应取消。
		pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); 
		
		//执行p指向的那个节点函数
		(p->do_task)(p->arg);
		
		//设置线程当前能响应。(线程说,我做完这个任务了,要杀要打请随便)
		pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);

		//释放p这个节点。
		free(p);
	}

	pthread_exit(NULL);
}

bool init_pool(thread_pool *pool, unsigned int threads_number)
{
	//1. 初始化互斥锁。
	pthread_mutex_init(&pool->lock, NULL);
	
	//2. 初始化条件变量。
	pthread_cond_init(&pool->cond, NULL);

	//3. 设置当前系统的标志位为开启状态。
	pool->shutdown = false;
	
	//4. 为任务队列的头节点申请空间。
	pool->task_list = malloc(sizeof(struct task));
	
	//6. 为储存ID号的空间申请内存空间,最多容纳20个线程。
	pool->tids = malloc(sizeof(pthread_t) * MAX_ACTIVE_THREADS);

	//7. 错误判断,如果空间申请失败,那么初始化失败。
	if(pool->task_list == NULL || pool->tids == NULL)
	{
		perror("allocate memory error");
		return false;
	}

	//8. 为任务队列的头节点的指针域赋值。
	pool->task_list->next = NULL;
	
	//9. 设置线程池中最大等待任务个数为1000个。
	pool->max_waiting_tasks = MAX_WAITING_TASKS;
	
	//10. 当前线程池没有任务。
	pool->waiting_tasks = 0;
	
	//11. 初始化线程的个数。
	pool->active_threads = threads_number;

	//12. 根据你的需求,来创建线程。
	int i;
	for(i=0; i<pool->active_threads; i++)
	{
		if(pthread_create(&((pool->tids)[i]), NULL,routine, (void *)pool) != 0)
		{
			perror("create threads error");
			return false;
		}
	}

	//13. 初始化成功。
	return true;
}

bool add_task(thread_pool *pool,void *(*do_task)(void *arg), void *arg)
{
	//1. 新任务必须要申请新节点,新节点必须要申请新的空间。
	struct task *new_task = malloc(sizeof(struct task));
	if(new_task == NULL)
	{
		perror("allocate memory error");
		return false;
	}
	
	//2. 为新节点的数据域赋值。
	new_task->do_task = do_task;  
	new_task->arg = arg; 

	//3. 为新节点的指针域赋值。
	new_task->next = NULL;  
	
	//4. 上锁。(在线程池中,只要涉及到任务队列,都要上锁)
	pthread_mutex_lock(&pool->lock);
	
	//5. 如果当前等待的任务个数>=1000
	if(pool->waiting_tasks >= MAX_WAITING_TASKS)
	{
		//解锁
		pthread_mutex_unlock(&pool->lock);
		
		//输出一句话报错
		fprintf(stderr, "too many tasks.\n");
		
		//释放刚才申请的空间。
		free(new_task);

		//添加任务失败
		return false;
	}
	
	//6. 寻找最后一个节点
	struct task *tmp = pool->task_list;
	while(tmp->next != NULL)
		tmp = tmp->next;

	//从循环出来,tmp->next一定为NULL,说明tmp就是指向最后一个节点。
	//让最后一个节点的指针域指向新节点。
	tmp->next = new_task;
	
	//7. 当前等待的任务个数+1
	pool->waiting_tasks++;

	//8. 解锁
	pthread_mutex_unlock(&pool->lock);

	//9. 随机唤醒条件变量中的一个线程起来任务。
	pthread_cond_signal(&pool->cond);
	
	//10. 添加成功。
	return true;
}

int add_thread(thread_pool *pool, unsigned additional_threads)  //5
{
	//如果你想新增0条线程,那么函数直接返回。
	if(additional_threads == 0)
		return 0; 

	//总线程个数           = 当前线程池中线程个数 + 新增条数
	unsigned total_threads = pool->active_threads + additional_threads;
	//         7           =          2           +       5
						
	int i, actual_increment = 0;
	
	for(i = pool->active_threads;                          // i=2 
	      i < total_threads && i < MAX_ACTIVE_THREADS;     //i必须小于7并且小于20,就可以创建。
	      i++) 
	   {
		if(pthread_create(&((pool->tids)[i]),NULL, routine, (void *)pool) != 0)
		{
			perror("add threads error");
			if(actual_increment == 0)   //如果创建线程时,发现一条都没有到,那么直接返回-1
				return -1;

			break;
		}
		actual_increment++;  //真正创建的条数+1
	}

	//从循环出来时,actual_increment就是真正创建线程的条数。

	//当前活跃的线程增加了actual_increment这么条。
	pool->active_threads += actual_increment; 

	//最后返回新增的条数。
	return actual_increment; 
}


int remove_thread(thread_pool *pool, unsigned int removing_threads)
{
	//如果想删除0条线程,那么就返回当前线程池中剩余的条数。
	if(removing_threads == 0)
		return pool->active_threads; 

	// 剩余线程的条数     = 当前线程池中线程条数 - 你想删除的条数。
	int remaining_threads = pool->active_threads - removing_threads;
	//         5          =        8             -        3
	//         0          =        8             -        8
	//         -2         =        8             -        10
	
	//如果减完之后,余数是大于0的,那么结果按是你的结果。
	//如果减完之后,余数是等于0/小于0的,那么结果就等于1。
	remaining_threads = remaining_threads > 0 ? remaining_threads : 1;

	//取消你想删除的那么多的条线程。
	int i;  
	for(i=pool->active_threads-1; i>remaining_threads-1; i--)
	{	
		errno = pthread_cancel(pool->tids[i]); 
		if(errno != 0)
			break;
	}

	//如果一条都没有取消得了,返回-1
	if(i == pool->active_threads-1) 
		return -1;
	else
	{
		//如果至少取消了一条,那么也算成功。
		pool->active_threads = i+1; 
		return i+1; 
	}
}


bool destroy_pool(thread_pool *pool)
{
	//1. 先将系统标志位设置为true,代表线程池要关闭了
	pool->shutdown = true; 
	
	//2. 广播,通知所有的小孩醒来退出了。
	pthread_cond_broadcast(&pool->cond);  
	
	//3. 接合所有线程。
	int i;
	for(i=0; i<pool->active_threads; i++)
	{
		errno = pthread_join(pool->tids[i], NULL);

		if(errno != 0)
		{
			printf("join tids[%d] error: %s\n",
					i, strerror(errno));
		}
	
		else
			printf("[%u] is joined\n", (unsigned)pool->tids[i]);
		
	}

	//4. 将申请过的空间释放掉。
	free(pool->task_list);
	free(pool->tids);
	free(pool);

	//5. 销毁成功。
	return true;
}

线程池的简单实用main函数

#include "thread_pool.h"

void *mytask(void *arg) //线程的任务
{
	int n = *(int*)arg;

	//工作任务:余数是多少,就睡多少秒,睡完,任务就算完成
	printf("[%u][%s] ==> job will be done in %d sec...\n",
		(unsigned)pthread_self(), __FUNCTION__, n);

	sleep(n);

	printf("[%u][%s] ==> job done!\n",
		(unsigned)pthread_self(), __FUNCTION__);

	return NULL;
}

void *count_time(void *arg)
{
	int i = 0;
	while(1)
	{
		sleep(1);
		printf("sec: %d\n", ++i);
	}
}

int main(void)
{
	// 本线程用来显示当前流逝的秒数
	// 跟程序逻辑无关
	pthread_t a;
	pthread_create(&a, NULL, count_time, NULL);

	// 1, initialize the pool
	thread_pool *pool = malloc(sizeof(thread_pool));
	init_pool(pool, 2);
	//2个线程都在条件变量中睡眠

	// 2, throw tasks
	printf("throwing 3 tasks...\n");
	int aa = (rand()%10);
	int b = (rand()%10);
	int c = (rand()%10);
	
	add_task(pool, mytask, (void *)&aa);  //5
	add_task(pool, mytask, (void *)&b);   //6
	add_task(pool, mytask, (void *)&c);   //3

	// 3, check active threads number
	printf("current thread number: %d\n",
			remove_thread(pool, 0));//2
	sleep(9);

	// 4, throw tasks
	printf("throwing another 6 tasks...\n");
	
	int d,e,f,g,h,j;
	d = (rand()%10);
	e = (rand()%10);
	f = (rand()%10);
	g = (rand()%10);
	h = (rand()%10);
	j = (rand()%10);
	
	add_task(pool, mytask, (void *)&d);
	add_task(pool, mytask, (void *)&e);
	add_task(pool, mytask, (void *)&f);
	add_task(pool, mytask, (void *)&g);
	add_task(pool, mytask, (void *)&h);
	add_task(pool, mytask, (void *)&j);
	
	// 5, add threads
	add_thread(pool, 2);

	sleep(5);

	// 6, remove threads
	printf("remove 3 threads from the pool, "
	       "current thread number: %d\n",
			remove_thread(pool, 3));

	// 7, destroy the pool
	destroy_pool(pool);
	return 0;
}

通过线程池实现过线程文件复制

#include "head.h"

bool copydir(struct tpool *pool,char *src,char *dst,struct stat *info)
{
	if(access(dst,F_OK))
	{
		mkdir(dst,info->st_mode);
	}
	
	struct stat *fileinfo = (struct stat *)malloc(sizeof(struct stat));
	stat(dst,fileinfo);
	
	if(!S_ISDIR(fileinfo->st_mode))
	{
		printf("%s Not a directory!\n",dst);
		return false;
	}

	char src_path[50],dst_path[50],ori_path[50];
	
	bzero(ori_path,50);
	getcwd(ori_path,50); 
	
	chdir(src);           
	bzero(src_path,50);
	getcwd(src_path,50);
	
	chdir(ori_path);        
	chdir(dst);               
	bzero(dst_path,50);      
	getcwd(dst_path,50);
		
	DIR *dp = opendir(src_path);
	
	chdir(src_path);
	
	struct dirent *ep = NULL;
	
	while(1)
	{
		ep = readdir(dp);
		
		if(ep == NULL)
			break;
		
		if(strcmp(ep->d_name,".") == 0 ||
		   strcmp(ep->d_name,"..") == 0)
		   continue;
		   
		bzero(fileinfo,sizeof(struct stat));
		
		chdir(src_path);
		
		stat(ep->d_name,fileinfo);
		 
		if(S_ISREG(fileinfo->st_mode))
		{
			int *fd = calloc(2, sizeof(int));
				
			fd[0] = open(ep->d_name, O_RDONLY);
	
			chdir(dst_path);  
			fd[1] = open(ep->d_name, O_WRONLY|O_CREAT|O_TRUNC,fileinfo->st_mode);
						
			add_task(pool,mytask,(void *)fd); 	
		}
		
		if(S_ISDIR(fileinfo->st_mode))
		{
			chdir(dst_path);    
			mkdir(ep->d_name,fileinfo->st_mode);
			chdir(ep->d_name);
			
			char new_path[50];
			getcwd(new_path,50);
			
			chdir(src_path);
			copydir(pool,ep->d_name,new_path,fileinfo);
		}		
	}
}

void copyfile(int src,int dst)
{
	char buf[1024];
	int r_num;
	
	while(1)
	{
		r_num = read(src,buf,1024);
		
		if(r_num <= 0)
			break;
		
		write(dst,buf,r_num);
	}
	
	return;
}

void *mytask(void *arg)
{
	int *fd = (int *)arg;
	
	copyfile(fd[0],fd[1]);
}

int main(int argc,char *argv[]) // ./copy file1 file2   ||  ./copy dir1 dir2  || ./copy file dir/
{
	umask(0000);
	if(argc != 3)
	{
		printf("argc error!\n");
		exit(0);
	}
	
	struct tpool *pool = malloc(sizeof(struct tpool));
	
	init_pool(pool,20);
	
	struct stat *fileinfo = malloc(sizeof(struct stat));
	stat(argv[1],fileinfo);

	struct stat *dstfileinfo = malloc(sizeof(struct stat));
	stat(argv[2],dstfileinfo);
	
	if(S_ISREG(fileinfo->st_mode) && !S_ISDIR(dstfileinfo->st_mode))
	{
		
		int *fd = calloc(2, sizeof(int));
		
		fd[0] = open(argv[1],O_RDONLY);
		
		fd[1] = open(argv[2],O_WRONLY|O_CREAT|O_TRUNC,fileinfo->st_mode);	
		
		if(fd[0] == -1 || fd[1] == -1)
		{
			exit(0);		
		}
		
		add_task(pool,mytask,(void *)fd);
	}
	
	if(S_ISREG(fileinfo->st_mode) && S_ISDIR(dstfileinfo->st_mode))
	{
		int *fd = calloc(2, sizeof(int));
		
		fd[0] = open(argv[1],O_RDONLY);
		
		chdir(argv[2]);
		fd[1] = open(argv[1],O_WRONLY|O_CREAT|O_TRUNC,fileinfo->st_mode);
		
		if(fd[0] == -1 || fd[1] == -1)
		{
			exit(0);		
		}
		
		add_task(pool,mytask,(void *)fd);
	}
	
	if(S_ISDIR(fileinfo->st_mode))
	{
		copydir(pool,argv[1],argv[2],fileinfo);
	}
	
	destroy_pool(pool);
	
	return 0;
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值