基于线程池的目录拷贝项目

项目要求

1)实现文件与文件的拷贝
2)实现目录与目录的拷贝
3)文件与文件的复制 目标文件是否可以绝对/相对路径复制
4)目录与目录的复制 目标目录是否可以绝对/相对路径复制
5)能根据实际情况实现特定要求下的拷贝操作

main.c

#include "thread_pool.h"

int main(int argc,char *argv[])
{
	//初始化线程池,创建3条线程
	thread_pool* pool = malloc(sizeof(thread_pool));
	init_pool(pool, 3);
	
	if(argc != 3)
	{
		printf("输入参数数目错误,请重新输入...\n");
		return -1;
	}
	
	//创建结构体,获取源文件和目录文件
	file_name fileName;
	strcpy(fileName.src,argv[1]);
	strcpy(fileName.dst,argv[2]);
	
	//定义源文件的文件结构体指针指向源文件,并开辟堆区空间,用于存放内容
	struct stat* source_file = malloc(sizeof(struct stat));
	stat(fileName.src,source_file);
	
	//定义目的文件的文件结构体指针指向目的文件,并开辟堆区空间,用于存放内容
	struct stat* target_file = malloc(sizeof(struct stat));
	stat(fileName.dst,target_file);
	
	//对拷贝类型进行判断,从而使用不同的拷贝函数(文件到文件,目录到目录,文件到目录)
	file_file(source_file,target_file,pool,(char *)&fileName.src,(char *)&fileName.dst);
	dir_dir(source_file,target_file,pool,(char *)&fileName.src,(char *)&fileName.dst);
	file_to_dir(source_file,target_file,pool,(char *)&fileName.src,(char *)&fileName.dst);

	//销毁线程池
	destroy_pool(pool);
	
	return 0;
}

thread_pool.c

#include "thread_pool.h"

void handler(void *arg)
{
	printf("[%u] is ended.\n",
		(unsigned)pthread_self());

	pthread_mutex_unlock((pthread_mutex_t *)arg);
}

// 子线程工作的任务
void *routine(void *arg)
{
	#ifdef DEBUG
	printf("[%u] is started.\n",
		(unsigned)pthread_self());
	#endif

	thread_pool *pool = (thread_pool *)arg;
	struct task *p;

	while(1)
	{
		/*
		** push a cleanup functon handler(), make sure that
		** the calling thread will release the mutex properly
		** even if it is cancelled during holding the mutex.
		**
		** NOTE:
		** pthread_cleanup_push() is a macro which includes a
		** loop in it, so if the specified field of codes that 
		** paired within pthread_cleanup_push() and pthread_
		** cleanup_pop() use 'break' may NOT break out of the
		** truely loop but break out of these two macros.
		** see line 61 below.
		*/
		// 保存锁资源,防止线程被取消导致死锁
		// 如果线程被取消会调用handler函数
		//================================================//
		pthread_cleanup_push(handler, (void *)&pool->lock);
		pthread_mutex_lock(&pool->lock);
		//================================================//

		// 1, no task, and is NOT shutting down, then wait
		// 没有任务并且线程池正常工作,那么线程休眠
		while(pool->waiting_tasks == 0 && !pool->shutdown)
		{
			pthread_cond_wait(&pool->cond, &pool->lock);
		}

		// 2, no task, and is shutting down, then exit
		// 没有任务,并且线程池要结束,解锁,所有线程退出
		if(pool->waiting_tasks == 0 && pool->shutdown == true)
		{
			pthread_mutex_unlock(&pool->lock);
			pthread_exit(NULL); // CANNOT use 'break';
		}

		// 3, have some task, then consume it
		// 有任务,线程取任务并执行
		p = pool->task_list->next;
		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->do_task)(p->arg);
		// 线程恢复取消
		pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);

		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);
	
	// false表示线程正常工作,true表示销毁线程池
	pool->shutdown = false;
	// 给任务链表分配空间
	pool->task_list = malloc(sizeof(struct task));
	// 给线程分配空间,最多是20条线程
	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;
	// 最大等待任务1000个节点
	pool->max_waiting_tasks = MAX_WAITING_TASKS;
	// 等待任务没有
	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;
		}

		#ifdef DEBUG
		printf("[%u]:[%s] ==> tids[%d]: [%u] is created.\n",
			(unsigned)pthread_self(), __FUNCTION__,
			i, (unsigned)pool->tids[i]);
		#endif
	}

	return true;
}

// 添加任务
bool add_task(thread_pool *pool,
	      void *(*do_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->do_task = do_task;//mytask
	new_task->arg = arg;
	new_task->next = NULL;

	//============ LOCK =============//
	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++;

	//=========== UNLOCK ============//
	pthread_mutex_unlock(&pool->lock);
	//===============================//

	#ifdef DEBUG
	printf("[%u][%s] ==> a new task has been added.\n",
		(unsigned)pthread_self(), __FUNCTION__);
	#endif
	// 链表有任务,广播通知睡觉的线程起来工作
	pthread_cond_signal(&pool->cond);
	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");

			// no threads has been created, return fail
			if(actual_increment == 0)
				return -1;

			break;
		}
		actual_increment++; 

		#ifdef DEBUG
		printf("[%u]:[%s] ==> tids[%d]: [%u] is created.\n",
			(unsigned)pthread_self(), __FUNCTION__,
			i, (unsigned)pool->tids[i]);
		#endif
	}

	pool->active_threads += actual_increment;
	return actual_increment;
}

// 删除线程
int remove_thread(thread_pool *pool, unsigned int removing_threads)
{
	if(removing_threads == 0)
		return pool->active_threads;

	int remaining_threads = pool->active_threads - removing_threads;
	// 最低要保留一条线程,不能团灭
	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;

		#ifdef DEBUG
		printf("[%u]:[%s] ==> cancelling tids[%d]: [%u]...\n",
			(unsigned)pthread_self(), __FUNCTION__,
			i, (unsigned)pool->tids[i]);
		#endif
	}

	if(i == pool->active_threads-1)
		return -1;
	else
	{
		pool->active_threads = i+1;
		return i+1;
	}
}

// 销毁线程
bool destroy_pool(thread_pool *pool)
{
	// 1, activate all threads
	pool->shutdown = true;
	// 唤醒正在睡觉的线程
	pthread_cond_broadcast(&pool->cond);

	// 2, wait for their exiting
	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]);
		
	}

	// 3, free memories
	// 释放资源
	free(pool->task_list);
	free(pool->tids);
	free(pool);

	return true;
}

void copyfile(int src,int dst)
{
	char buf[100] = { 0 };	
	int ret = 0;
	
	while(1)
	{
		ret = read(src,buf,100);
		
		if(ret == 0)
		{
			break;
		}
		
		write(dst,buf,ret);
	}
	
	close(src);
	close(dst);
}

void* task(void* arg)
{
	//调用复制文件的函数
	int* fd = (int *)arg;
	
	copyfile(fd[0],fd[1]);
	
	usleep(100);
}

void file_file(struct stat* source_file,struct stat* target_file,thread_pool* pool,char* src_file,char *dst_file)
{
	//源文件是文件,目标文件不是目录
	if(S_ISREG(source_file->st_mode) && !S_ISDIR(target_file->st_mode))
	{
		printf("源文件是普通文件,目标文件不是目录\n");
		printf("开始拷贝文件:%s ----> %s\n",src_file,dst_file);
		
		int* fd = calloc(2,sizeof(int));
		
		//打开源文件
		fd[0] = open(src_file,O_RDWR);
		fd[1] = open(dst_file,O_RDWR);
		
		//添加任务
		add_task(pool,task,(void *)fd);
	
	}
}


bool copydir(thread_pool* pool,char* src,char* dst,struct stat* info)
{	
	//定义一个stat结构体指针,开辟堆区空间
	struct stat* fileinfo = malloc(sizeof(struct stat));
	stat(dst,fileinfo);
	
	if(!S_ISDIR(fileinfo->st_mode))
	{
		printf("%s不是目录文件!\n",dst);
		return false;
	}
 
	char current_path[100] = {0};//当前路径
	char from_path[100] = {0};//源目录路径
	char dst_path[100] = {0};//目标目录路径
	
	//获取当前的路径
	getcwd(current_path,100);
	
	//获取源文件的路径存在buf里面	
	chdir(src);           
	getcwd(from_path,100);
	
	chdir(current_path); 	
	chdir(dst);               
	getcwd(dst_path,100);
	
	//打开目录
	DIR* dp = opendir(from_path);
	
	//切换到目录里面去
	chdir(from_path);
	
	//通过读目录将文件名读出来
	while(1)
	{
		struct dirent* ep = readdir(dp);
		if(ep == NULL)
		{
			break;
		}
		
		//条件判断(如果读取的文件是'.'和'..'不打印)
		if(ep->d_name[0] == '.')
			continue;
 
		printf("ep->d_name(文件名字):%s\n",ep->d_name);
		
		bzero(fileinfo,sizeof(struct stat));
		
		chdir(from_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,fileinfo->st_mode);
					
			usleep(100);
			
			add_task(pool,task,(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[100];
			getcwd(new_path,100);
			
			chdir(from_path);
			copydir(pool,ep->d_name,new_path,fileinfo);
 
		}
	}	
}
	
void dir_dir(struct stat* source_file,struct stat* target_file,thread_pool* pool,char* src_file,char *dst_file)
{
	//判断是否是目录文件
	if(S_ISDIR(source_file->st_mode))
	{
		printf("源文件是目录,目标文件是目录\n");
		printf("开始拷贝目录:%s ----> %s\n",src_file,dst_file);
				
		//拷贝目录文件
		copydir(pool,src_file,dst_file,source_file);
		
	}
}

void file_to_dir(struct stat* source_file,struct stat* target_file,thread_pool* pool,char* src_file,char* dst_file)
{
	if(S_ISREG(source_file->st_mode) && S_ISDIR(target_file->st_mode))
	{
		//定义一个stat结构体指针,开辟堆区空间
		struct stat* fileinfo = malloc(sizeof(struct stat));
		stat(dst_file,fileinfo);

		char dst_path[100] = {0};//目标目录路径
		char current_path[100] = {0};//当前路径

		//获取当前的路径
		getcwd(current_path,100);
			
		chdir(dst_file);               
		getcwd(dst_path,100);
		chdir(current_path); 

		int* fd = calloc(2, sizeof(int));

		fd[0] = open(src_file,O_RDWR|O_CREAT,source_file->st_mode);
		if(fd[0] == -1)
		{
			printf("open fail\n");
		}
		
		//打开目录
		DIR* dp = opendir(dst_file);
		
		//切换到目录里面去
		chdir(dst_path);

		while (1)
		{
			struct dirent* ep = readdir(dp);
			if(ep == NULL)
			{
				break;
			}
				
			//条件判断(如果读取的文件是'.'和'..'不打印)
			if(ep->d_name[0] == '.')
				continue;
		
			printf("ep->d_name(文件名字):%s\n",ep->d_name);	
			
			//源文件是文件,目标文件是目录
			if(S_ISREG(source_file->st_mode) && S_ISDIR(target_file->st_mode))
			{
				printf("源文件是普通文件,目标文件是目录\n");
				
				
				fd[1] = open(src_file,O_WRONLY|O_CREAT,target_file->st_mode);
				if(fd[1] == -1)
				{
					printf("open fail\n");
				}

				//添加任务
				add_task(pool,task,(void *)fd);
			}
		}
	}

}

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>

#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>

#include<dirent.h>

#define MAX_WAITING_TASKS	1000
#define MAX_ACTIVE_THREADS	20

typedef struct file_name
{
	char src[100];
	char dst[100];
}file_name;

// 任务
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;//线程销毁

	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);
void file_to_dir(struct stat* source_file,struct stat* target_file,thread_pool* pool,char* src_file,char* dst_file);
void dir_dir(struct stat* source_file,struct stat* target_file,thread_pool* pool,char* src_file,char *dst_file);
bool copydir(thread_pool* pool,char* src,char* dst,struct stat* info);
void file_file(struct stat* source_file,struct stat* target_file,thread_pool* pool,char* src_file,char *dst_file);
void* task(void* arg);
void copyfile(int src,int dst);


#endif

Makefile

CC = gcc
CFLAGS = -O -lpthread

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

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

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

.PHONY:all clean

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值