Linux C系统编程:使用线程池,实现cp功能


Linux C系统编程:使用线程池,实现cp功能

线程池的定义

         什么是线程池?简单点说,线程池就是有一堆已经创建好了的线程,初始它们都处于空闲等待状态,当有新的任务需要处理的时候,就从这个池子里面取一个空闲等待的线程来处理该任务,当处理完成了就再次把该线程放回池中,以供后面的任务使用。当池子里的线程全都处理忙碌状态时,线程池中没有可用的空闲等待线程,此时,根据需要选择创建一个新的线程并置入池中,或者通知任务线程池忙,稍后再试。

 

为什么要用线程池?

         我们说,线程的创建和销毁比之进程的创建和销毁是轻量级的,但是当我们的任务需要大量进行大量线程的创建和销毁操作时,这个消耗就会变成的相当大。比如,当你设计一个压力性能测试框架的时候,需要连续产生大量的并发操作,这个是时候,线程池就可以很好的帮上你的忙。线程池的好处就在于线程复用,一个任务处理完成后,当前线程可以直接处理下一个任务,而不是销毁后再创建,非常适用于连续产生大量并发任务的场合。

 

线程池工作原理

         线程池中每一个线程的工作过程如下:

 线程的工作流程

1: 线程的工作流程

         线程池的任务就在于负责这些线程的创建,销毁和任务处理参数传递、唤醒和等待。

1.      创建若干线程,置入线程池

2.      任务达到时,从线程池取空闲线程

3.      取得了空闲线程,立即进行任务处理

4.      否则新建一个线程,并置入线程池,执行3

5.      如果创建失败或者线程池已满,根据设计策略选择返回错误或将任务置入处理队列,等待处理

6.      销毁线程池

 

2:线程池的工作原理

 

下面是根据老师给的代码,加以修改,实现Linux系统cp命令功能的代码实现:

头文件: 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 *(*task)(void *arg);
	void *arg;

	struct task *next;
};

//线程池
typedef struct thread_pool
{
	pthread_mutex_t lock;//互斥锁
	pthread_cond_t  cond;//条件变量
	struct task *task_list;//任务队列

	pthread_t *tids;//线程id

	unsigned waiting_tasks;//等待任务
	unsigned active_threads;//

	bool shutdown;//停始状态
}thread_pool;

struct file
{
	char srcfile[1024];
	char dstfile[1024];
};

//初始化线程池
bool
init_pool(thread_pool *pool,
          unsigned int threads_number);

//新增任务
bool
add_task(thread_pool *pool,
         void *(*task)(void *arg),
         void *arg);

//新增线程
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);

//copy函数
void *(*copy)(void * arg);

#endif

线程池:thread_pool.c

#include "thread_pool.h"

//互斥锁解锁
void handler(void *arg)
{

	pthread_mutex_unlock((pthread_mutex_t *)arg);
}

//
void *routine(void *arg)
{
	thread_pool *pool = (thread_pool *)arg;
	struct task *p;//声明一个任务头节点
	printf("runtone... ...\n");

	while(1)
	{

		pthread_cleanup_push(handler, (void *)&pool->lock);//线程清理函数1
		pthread_mutex_lock(&pool->lock);//上锁


		while(pool->waiting_tasks == 0 && !pool->shutdown)//a.非停止状态
		{
			pthread_cond_wait(&pool->cond, &pool->lock);
		}


		if(pool->waiting_tasks == 0 && pool->shutdown == true)//b.停止状态
		{
			pthread_mutex_unlock(&pool->lock);//互斥锁解锁
			pthread_exit(NULL);//退出线程
		}


		p = pool->task_list->next;//指向任务队列下一个任务节点
		pool->task_list->next = p->next;//任务头节点的下一个赋值给线程池的变量
		pool->waiting_tasks--;//任务等待队列减1


		pthread_mutex_unlock(&pool->lock);//解锁
		pthread_cleanup_pop(0);//2


		pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);//线程的分离相关知识
		(p->task)(p->arg);	
		printf("runtine is running ...\n");
		pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
		free(p->arg);
		free(p);
	}

	pthread_exit(NULL);
}
//初始化线程池
bool init_pool(thread_pool *pool, unsigned int threads_number)
{
	pthread_mutex_init(&pool->lock, NULL);//互斥锁
	pthread_cond_init(&pool->cond, NULL); //条件变量初始化,pool->cond条件变量

	pool->shutdown = false;//非关闭状态
	pool->task_list = malloc(sizeof(struct task));//为任务链表申请内存空间
	pool->tids = malloc(sizeof(pthread_t) * MAX_ACTIVE_THREADS);//为所有线程申请内存空间

	if(pool->task_list == NULL || pool->tids == NULL)//判断任务是否有任务、是否有线程
	{
		perror("allocate memory error");
		return false;
	}

	pool->task_list->next = NULL;

	pool->waiting_tasks = 0;
	pool->active_threads = threads_number;//当前线程个数

	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;
		}
	}

	return true;
}
//新增任务
bool add_task(thread_pool *pool,
			void *(*task)(void *arg), void *arg)
{
	struct task *new_task = malloc(sizeof(struct task));//为新任务申请内存空间
	if(new_task == NULL)
	{
		perror("allocate memory error");
		return false;
	}
	//给新任务数据赋值
	new_task->task = task;
	new_task->arg = arg;
	new_task->next = NULL;
	printf("new_task init successfully!\n");
	//
	pthread_mutex_lock(&pool->lock);//互斥锁上锁
	if(pool->waiting_tasks >= MAX_WAITING_TASKS)//判断等待任务数是否大于最大数
	{
		pthread_mutex_unlock(&pool->lock);

		fprintf(stderr, "too many tasks.\n");
		free(new_task);

		return false;
	}
	//把新的任务插入任务链表
	struct task *tmp = pool->task_list;
	while(tmp->next != NULL)
		tmp = tmp->next;//指向链表尾

	tmp->next = new_task;//把新任务节点插到链表尾
	pool->waiting_tasks++;//任务等待加1
	
	printf("insert new_task to pthread_pool tasklink tail successfully!\n");
	
	pthread_mutex_unlock(&pool->lock);//互斥锁解锁
	pthread_cond_signal(&pool->cond);//发送一个信号给另外一个正在处于阻塞等待状态的线程,使其脱离阻塞状态,继续执行.
	
	printf("close add_task successfully!\n");
	return true;
}
//新增线程,返回进程数
int add_thread(thread_pool *pool, unsigned additional_threads)
{
	if(additional_threads == 0)
		return 0;

	unsigned total_threads =
		     pool->active_threads + additional_threads;//总线程数

	int i, actual_increment = 0;
	//对线程池中的线程进行创建
	for(i = pool->active_threads;
	    i < total_threads && i < MAX_ACTIVE_THREADS;
	    i++)
	{
		if(pthread_create(&((pool->tids)[i]),
				NULL, routine, (void *)pool) != 0)
		{
			perror("add threads error");

			if(actual_increment == 0)
				return -1;

			break;
		}
		actual_increment++; //对实际创建的进程数计数
	}

	pool->active_threads += actual_increment;//更新活跃进程总数
	return actual_increment;
}
//移除线程
int remove_thread(thread_pool *pool, unsigned int removing_threads)
{
	if(removing_threads == 0)//移除个数为0,直接返回
		return pool->active_threads;

	int remain_threads = pool->active_threads - removing_threads;
	remain_threads = remain_threads>0 ? remain_threads:1;

	int i;
	for(i=pool->active_threads-1; i>remain_threads-1; i--)
	{
		errno = pthread_cancel(pool->tids[i]);
		if(errno != 0)
			break;
	}

	if(i == pool->active_threads-1)
		return -1;
	else
	{
		pool->active_threads = i+1;
		return i+1;
	}
}
//销毁线程池
bool destroy_pool(thread_pool *pool)
{

	pool->shutdown = true;
	pthread_cond_broadcast(&pool->cond);

	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]);
		
	}

	free(pool->task_list);
	free(pool->tids);
	free(pool);

	return true;
}

主函数:copy.c

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <dirent.h>
#include <stdbool.h>
#include <string.h>

#include "thread_pool.h"

//拷贝普通文件,成功返回0,失败返回-1
void *copyregfile(void *arg)
{
	struct file * dofile = (struct file *)arg;
	printf("copyregfile is running...\n");
	struct stat file_stat;/*struct stat这个结构体是用来描述一个linux系统文件系统中的文件属性的结构*/
	stat(dofile->srcfile, &file_stat);//获取文件的属性

	int srcfd,dstfd;
	srcfd = open(dofile->srcfile,O_RDONLY);
	dstfd = open(dofile->dstfile,O_CREAT | O_TRUNC | O_RDWR,file_stat.st_mode);//以源文件的类型和权限创建文件

	if(srcfd == -1 || dstfd == -1)
	{
		perror("open file:");
		
		//return -1;
	}

	int nread;
	char buf[100];
	while((nread = read(srcfd,buf,100)) > 0)
	{
		if( write(dstfd,buf,nread) == -1)
		{
			break;
		}
	}

	close(dstfd);
	return NULL;
}



//拷贝目录,成功返回0.失败返回-1
int copydir(struct file* dofile)
{
	printf("copydir is running... \n");
	struct stat file_stat;
	stat(dofile->srcfile,&file_stat); //获取文件的属性
	mkdir(dofile->dstfile,file_stat.st_mode); //以源目录的类型和目录来创建一个目录

	DIR *srcdir = opendir(dofile->srcfile); //打开源目录
	struct dirent *dp;
	struct file *tmpfile = malloc(sizeof(struct file)); //对本目录下的所有文件进行拷贝操作

	while( (dp = readdir(srcdir))!=NULL )
	{
		memset(tmpfile,0,sizeof(struct file));

		if(dp->d_name[0] == '.') //如果文件为. 或者 .. 则跳过
		{
			continue;
		}

		sprintf(tmpfile->srcfile,"%s/%s",dofile->srcfile,dp->d_name);
		sprintf(tmpfile->dstfile,"%s/%s",dofile->dstfile,dp->d_name);
		

		struct stat tmpstat;
		stat(tmpfile->srcfile,&tmpstat);

		if(S_ISREG(tmpstat.st_mode))//如果为普通文件,则拷贝
		{
			copyregfile(tmpfile);  //这个是任务
			printf("%s\n",tmpfile->srcfile);
		}
		else if(S_ISDIR(tmpstat.st_mode))//如果为目录,则递归
		{
			copydir(tmpfile);
			printf("%s\n",tmpfile->srcfile);
		}

	}
	
	closedir(srcdir);
	free(tmpfile); 
	return 0;
}



int main(int argc,char *argv[])
{
	printf("enter\n");
	thread_pool *pool = malloc(sizeof(thread_pool));
	init_pool(pool, 20);
	//struct file *dofile = (struct file*)arg;
	if(argc != 3)
	{
		printf("Please run : ./%s xxx yyy\n",argv[0]);
		return -1;
	}
	
	struct file dofile;
	strcpy(dofile.srcfile,argv[1]);
	strcpy(dofile.dstfile,argv[2]);
	
	struct stat srcstat;
	stat(dofile.srcfile,&srcstat);
	
	if(S_ISREG(srcstat.st_mode))//如果为普通文件,则拷贝
	{
		add_task(pool,copyregfile,(void *)&dofile);
	}
	else if(S_ISDIR(srcstat.st_mode))//如果为目录,则递归
	{
		copydir(&dofile);
	}
	printf("current thread number: %d\n",
		remove_thread(pool, 0));	
	
			
	destroy_pool(pool);
	return 0;
}

编译:Makefile

CC = gcc
CFLAGS = -O0 -Wall -g -lpthread

test:thread_pool.c copy.c
	$(CC) $^ -o $@ $(CFLAGS)

debug:main.c thread_pool.c
	$(CC) $^ -o $@ $(CFLAGS) -DDEBUG

clean:
	$(RM) .*.sw? test debug *.o

.PHONY:all clean

运行:
./test  源路径/文件 目标路径/文件


CC = gcc
CFLAGS = -O0 -Wall -g -lpthread

test:thread_pool.c copy.c
	$(CC) $^ -o $@ $(CFLAGS)

debug:main.c thread_pool.c
	$(CC) $^ -o $@ $(CFLAGS) -DDEBUG

clean:
	$(RM) .*.sw? test debug *.o

.PHONY:all clean


 


#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <dirent.h>
#include <stdbool.h>
#include <string.h>

#include "thread_pool.h"

//拷贝普通文件,成功返回0,失败返回-1
void *copyregfile(void *arg)
{
	struct file * dofile = (struct file *)arg;
	printf("copyregfile is running...\n");
	struct stat file_stat;/*struct stat这个结构体是用来描述一个linux系统文件系统中的文件属性的结构*/
	stat(dofile->srcfile, &file_stat);//获取文件的属性

	int srcfd,dstfd;
	srcfd = open(dofile->srcfile,O_RDONLY);
	dstfd = open(dofile->dstfile,O_CREAT | O_TRUNC | O_RDWR,file_stat.st_mode);//以源文件的类型和权限创建文件

	if(srcfd == -1 || dstfd == -1)
	{
		perror("open file:");
		
		//return -1;
	}

	int nread;
	char buf[100];
	while((nread = read(srcfd,buf,100)) > 0)
	{
		if( write(dstfd,buf,nread) == -1)
		{
			break;
		}
	}

	close(dstfd);
	return NULL;
}



//拷贝目录,成功返回0.失败返回-1
int copydir(struct file* dofile)
{
	printf("copydir is running... \n");
	struct stat file_stat;
	stat(dofile->srcfile,&file_stat); //获取文件的属性
	mkdir(dofile->dstfile,file_stat.st_mode); //以源目录的类型和目录来创建一个目录

	DIR *srcdir = opendir(dofile->srcfile); //打开源目录
	struct dirent *dp;
	struct file *tmpfile = malloc(sizeof(struct file)); //对本目录下的所有文件进行拷贝操作

	while( (dp = readdir(srcdir))!=NULL )
	{
		memset(tmpfile,0,sizeof(struct file));

		if(dp->d_name[0] == '.') //如果文件为. 或者 .. 则跳过
		{
			continue;
		}

		sprintf(tmpfile->srcfile,"%s/%s",dofile->srcfile,dp->d_name);
		sprintf(tmpfile->dstfile,"%s/%s",dofile->dstfile,dp->d_name);
		

		struct stat tmpstat;
		stat(tmpfile->srcfile,&tmpstat);

		if(S_ISREG(tmpstat.st_mode))//如果为普通文件,则拷贝
		{
			copyregfile(tmpfile);  //这个是任务
			printf("%s\n",tmpfile->srcfile);
		}
		else if(S_ISDIR(tmpstat.st_mode))//如果为目录,则递归
		{
			copydir(tmpfile);
			printf("%s\n",tmpfile->srcfile);
		}

	}
	
	closedir(srcdir);
	free(tmpfile); 
	return 0;
}



int main(int argc,char *argv[])
{
	printf("enter\n");
	thread_pool *pool = malloc(sizeof(thread_pool));
	init_pool(pool, 20);
	//struct file *dofile = (struct file*)arg;
	if(argc != 3)
	{
		printf("Please run : ./%s xxx yyy\n",argv[0]);
		return -1;
	}
	
	struct file dofile;
	strcpy(dofile.srcfile,argv[1]);
	strcpy(dofile.dstfile,argv[2]);
	
	struct stat srcstat;
	stat(dofile.srcfile,&srcstat);
	
	if(S_ISREG(srcstat.st_mode))//如果为普通文件,则拷贝
	{
		add_task(pool,copyregfile,(void *)&dofile);
	}
	else if(S_ISDIR(srcstat.st_mode))//如果为目录,则递归
	{
		copydir(&dofile);
	}
	printf("current thread number: %d\n",
		remove_thread(pool, 0));	
	
			
	destroy_pool(pool);
	return 0;
}


 


#include "thread_pool.h"

//互斥锁解锁
void handler(void *arg)
{

	pthread_mutex_unlock((pthread_mutex_t *)arg);
}

//
void *routine(void *arg)
{
	thread_pool *pool = (thread_pool *)arg;
	struct task *p;//声明一个任务头节点
	printf("runtone... ...\n");

	while(1)
	{

		pthread_cleanup_push(handler, (void *)&pool->lock);//线程清理函数1
		pthread_mutex_lock(&pool->lock);//上锁


		while(pool->waiting_tasks == 0 && !pool->shutdown)//a.非停止状态
		{
			pthread_cond_wait(&pool->cond, &pool->lock);
		}


		if(pool->waiting_tasks == 0 && pool->shutdown == true)//b.停止状态
		{
			pthread_mutex_unlock(&pool->lock);//互斥锁解锁
			pthread_exit(NULL);//退出线程
		}


		p = pool->task_list->next;//指向任务队列下一个任务节点
		pool->task_list->next = p->next;//任务头节点的下一个赋值给线程池的变量
		pool->waiting_tasks--;//任务等待队列减1


		pthread_mutex_unlock(&pool->lock);//解锁
		pthread_cleanup_pop(0);//2


		pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);//线程的分离相关知识
		(p->task)(p->arg);	
		printf("runtine is running ...\n");
		pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
		free(p->arg);
		free(p);
	}

	pthread_exit(NULL);
}
//初始化线程池
bool init_pool(thread_pool *pool, unsigned int threads_number)
{
	pthread_mutex_init(&pool->lock, NULL);//互斥锁
	pthread_cond_init(&pool->cond, NULL); //条件变量初始化,pool->cond条件变量

	pool->shutdown = false;//非关闭状态
	pool->task_list = malloc(sizeof(struct task));//为任务链表申请内存空间
	pool->tids = malloc(sizeof(pthread_t) * MAX_ACTIVE_THREADS);//为所有线程申请内存空间

	if(pool->task_list == NULL || pool->tids == NULL)//判断任务是否有任务、是否有线程
	{
		perror("allocate memory error");
		return false;
	}

	pool->task_list->next = NULL;

	pool->waiting_tasks = 0;
	pool->active_threads = threads_number;//当前线程个数

	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;
		}
	}

	return true;
}
//新增任务
bool add_task(thread_pool *pool,
			void *(*task)(void *arg), void *arg)
{
	struct task *new_task = malloc(sizeof(struct task));//为新任务申请内存空间
	if(new_task == NULL)
	{
		perror("allocate memory error");
		return false;
	}
	//给新任务数据赋值
	new_task->task = task;
	new_task->arg = arg;
	new_task->next = NULL;
	printf("new_task init successfully!\n");
	//
	pthread_mutex_lock(&pool->lock);//互斥锁上锁
	if(pool->waiting_tasks >= MAX_WAITING_TASKS)//判断等待任务数是否大于最大数
	{
		pthread_mutex_unlock(&pool->lock);

		fprintf(stderr, "too many tasks.\n");
		free(new_task);

		return false;
	}
	//把新的任务插入任务链表
	struct task *tmp = pool->task_list;
	while(tmp->next != NULL)
		tmp = tmp->next;//指向链表尾

	tmp->next = new_task;//把新任务节点插到链表尾
	pool->waiting_tasks++;//任务等待加1
	
	printf("insert new_task to pthread_pool tasklink tail successfully!\n");
	
	pthread_mutex_unlock(&pool->lock);//互斥锁解锁
	pthread_cond_signal(&pool->cond);//发送一个信号给另外一个正在处于阻塞等待状态的线程,使其脱离阻塞状态,继续执行.
	
	printf("close add_task successfully!\n");
	return true;
}
//新增线程,返回进程数
int add_thread(thread_pool *pool, unsigned additional_threads)
{
	if(additional_threads == 0)
		return 0;

	unsigned total_threads =
		     pool->active_threads + additional_threads;//总线程数

	int i, actual_increment = 0;
	//对线程池中的线程进行创建
	for(i = pool->active_threads;
	    i < total_threads && i < MAX_ACTIVE_THREADS;
	    i++)
	{
		if(pthread_create(&((pool->tids)[i]),
				NULL, routine, (void *)pool) != 0)
		{
			perror("add threads error");

			if(actual_increment == 0)
				return -1;

			break;
		}
		actual_increment++; //对实际创建的进程数计数
	}

	pool->active_threads += actual_increment;//更新活跃进程总数
	return actual_increment;
}
//移除线程
int remove_thread(thread_pool *pool, unsigned int removing_threads)
{
	if(removing_threads == 0)//移除个数为0,直接返回
		return pool->active_threads;

	int remain_threads = pool->active_threads - removing_threads;
	remain_threads = remain_threads>0 ? remain_threads:1;

	int i;
	for(i=pool->active_threads-1; i>remain_threads-1; i--)
	{
		errno = pthread_cancel(pool->tids[i]);
		if(errno != 0)
			break;
	}

	if(i == pool->active_threads-1)
		return -1;
	else
	{
		pool->active_threads = i+1;
		return i+1;
	}
}
//销毁线程池
bool destroy_pool(thread_pool *pool)
{

	pool->shutdown = true;
	pthread_cond_broadcast(&pool->cond);

	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]);
		
	}

	free(pool->task_list);
	free(pool->tids);
	free(pool);

	return true;
}


 

 

 

发布了5 篇原创文章 · 获赞 38 · 访问量 2万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章