- 思路:
1.创建初始化线程池 2.编写函数,其作用是递归查找目录下所有文件 3.将创建目录或者创建文件的任务添加到任务池中 4.完成目录的拷贝
2.线程池代码
#include "thread_pool.h"
#define TASK_MAX 1024
#define THREADS_MAX 20
void handle(void*arg)
{
thread_pool* pool = (thread_pool*)arg;
pthread_mutex_unlock(&pool->mutex);
}
//线程函数
void*thread_running(void* arg)
{
thread_pool* pool = (thread_pool*)arg;
struct task_node*p = NULL;//指向 要执行的任务节点
while(1)
{
//上锁之前注册一个清理函数,避免被取消死锁
pthread_cleanup_push(handle,pool);
//1.上锁访问任务队列
pthread_mutex_lock(&pool->mutex);
//2. 访问任务队列
// 无任务且线程池未关闭 wait
while(pool->h->num == 0 && !pool->shutdown)//被唤醒之后检测条件是否依然满足
{
pthread_cond_wait(&pool->cond, &pool->mutex);
//唤醒:
//1. 有任务
//2. 线程池要关闭的时候
}
// 无任务且线程池关闭 线程死亡
if(pool->h->num == 0 && pool->shutdown)
{
//先解锁在退出
pthread_mutex_unlock(&pool->mutex);
pthread_exit(NULL);
}
// 有任务开始在任务队列上拿去任务节点
p = pool->h->first;
pool->h->first = p->next;// pool->h->first = pool->h->first->next;
pool->h->num--;
//拿去任务之后解锁
pthread_mutex_unlock(&pool->mutex);
//出栈刚刚注册用不到的清理函数
pthread_cleanup_pop(0);
//3. 执行任务
//执行任务之前设置不可被取消
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
//执行任务
p->do_task(p->arg);// 使用函数指针调用任务函数
//执行任务之后设置可被取消
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
free(p);
p = NULL;
}
}
/*
init_pool:初始化一个线程池
@pool: 指向要初始的线程池
@thread_num:线程池中的活动线程数
返回值:
成功 返回true
失败 返回false
*/
bool init_pool(thread_pool*pool,int thread_num)
{
pthread_mutex_init(&pool->mutex, NULL);//初始互斥锁
pthread_cond_init(&pool->cond, NULL);//初始条件变量
pool->shutdown = false;//非 关闭状态
pool->task_max = TASK_MAX;
pool->h = malloc(sizeof(struct Head));//任务队列头节点指针
if(pool->h == NULL)
return false;
pool->h->first = pool->h->last = NULL;
pool->h->num = 0;//任务队列的节点数 0
pool->threads_max = THREADS_MAX;//线程最大数
if(thread_num > THREADS_MAX)
pool->threads_num = THREADS_MAX;//活动线程数
else
pool->threads_num = thread_num;
pool->tid = malloc(THREADS_MAX*sizeof(pthread_t));//指针,指向线程ID数组空间
if(pool->tid == NULL)
{
printf("失败:%d\n",__LINE__);
free(pool->h);
return false;
}
for(int i = 0; i < pool->threads_num; i++)
{
int re = pthread_create(&pool->tid[i], NULL, thread_running, pool);
if(re == -1)
{
perror("pthread_create :");
printf("失败:%d\n",__LINE__);
return false;
}
}
return true;
}
/*
add_task:往线程池中添加任务
@pool :执行要操作的线程池
@do_task:函数指针
执行要执行的任务函数
@arg: 任务函数 的参数
返回值:
成功 真
失败 假
*/
bool add_task(thread_pool*pool,void*(*do_task)(void*),void*arg)
{
if(pool == NULL)
{
printf("失败:%d\n",__LINE__);
return false;
}
//创建新节点
struct task_node*pnew = malloc(sizeof(*pnew));
if(pnew == NULL)
{
printf("失败:%d\n",__LINE__);
return false;
}
pnew->do_task = do_task;
pnew->arg = arg;
pnew->next = NULL;
//增加到任务队列上
pthread_mutex_lock(&pool->mutex);
//任务队列满队
if(pool->h->num == pool->task_max)
{
printf("失败:%d\n",__LINE__);
free(pnew);
printf("失败:%d\n",__LINE__);
pthread_mutex_unlock(&pool->mutex);
printf("失败:%d\n",__LINE__);
return false;
}
if(pool->h->num == 0)//空队列
{
pool->h->first = pool->h->last = pnew;
}
else
{
pool->h->last->next = pnew;
pool->h->last = pnew;
}
pool->h->num++;
pthread_mutex_unlock(&pool->mutex);
//唤醒任意一个睡眠线程
pthread_cond_signal(&pool->cond);
return true;
}
/*
*/
bool destroy_pool(thread_pool*pool)
{
pool->shutdown = true;//开关 是否关闭
//唤醒所有的睡眠线程
pthread_cond_broadcast(&pool->cond);
//等待所有活动线程死亡
for(int i = 0; i < pool->threads_num; i++)
{
pthread_join(pool->tid[i], NULL);
}
free(pool->h);
free(pool->tid);//指针,指向线程ID数组空间
pthread_mutex_destroy(&pool->mutex);//互斥锁
pthread_cond_destroy(&pool->cond);//条件变量
//free(pool);
return true;
}
3.线程池头文件代码
#ifndef __THREAD_POOL__
#define __THREAD_POOL__
#include <pthread.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
struct task_node
{
void*(*do_task)(void*);
void*arg;
struct task_node*next;
};
struct Head//队列头节点
{
struct task_node* first;
struct task_node* last;
int num;
};
//声明线程池类型
typedef struct thread_pool
{
pthread_mutex_t mutex;//互斥锁
pthread_cond_t cond;//条件变量
bool shutdown;//线程 是否关闭
int task_max;//最大任务数
struct Head*h;//任务队列头节点指针
int threads_max;//线程最大数
int threads_num;//活动线程数
pthread_t *tid;//指针,指向线程ID数组空间
//。。。
}thread_pool;
extern bool init_pool(thread_pool*pool,int thread_num);
extern bool add_task(thread_pool*pool,void*(*do_task)(void*),void*arg);
extern bool destroy_pool(thread_pool*pool);
#endif
4.main.c代码
#include <stdio.h>
#include "thread_pool.h"
#include <sys/types.h>
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
#include <stdlib.h>
#include <strings.h>
pthread_mutex_t g_mutex_cp;
int g_value_cp = 0;
typedef struct fname
{
char cp_FileArr[2048];//被拷贝的地址
char pa_FileArr[2048];//目标地址
DIR *dir;
struct dirent *p ;
thread_pool *pool; //线程池相关
}filename_t, *filename_p;
filename_t fileNames[20]; //防止多线程对同一份文件践踏
int Fnames = -1; //用作数组下标
//创建文件夹
void *cpfile(void * fileName)
{
filename_p fileName_pth = (filename_p)fileName;
mkdir(fileName_pth->pa_FileArr, 0777);
}
//创建文件
void *cpfile1(void * fileName)
{
filename_p fileName_pth = (filename_p)fileName;
int fd1 = open(fileName_pth->cp_FileArr, O_RDWR);
int fd2 = open(fileName_pth->pa_FileArr, O_RDWR | O_CREAT | O_TRUNC, 777);
int ret;
while(1)
{
char buf[16] = {0};
ret = read(fd1, buf, 16);
if(ret == 0) break;
write(fd2, buf, ret);
}
close(fd1);
close(fd2);
}
void Tast(filename_t fileName_F)
{
filename_t fileName = fileName_F;
fileName.p = readdir(fileName.dir);
if(fileName.p == NULL)
{
closedir(fileName.dir); //递归出口
return;
}//过滤 . 和 ..
else if(strcmp(fileName.p->d_name, "..") == 0 || strcmp(fileName.p->d_name, ".") == 0)
{
Tast(fileName);
}
else
{
char buf_cp[2048] = {0};//缓冲区
sprintf(buf_cp, "%s/%s", fileName.cp_FileArr, fileName.p->d_name); //当前被拷贝的路径
char buf_pa[2048] = {0};//缓冲区
sprintf(buf_pa, "%s/%s", fileName.pa_FileArr, fileName.p->d_name); //当前要拷贝的路径
if(fileName.p->d_type == DT_DIR)//如果是目录
{
Fnames++;
strcpy(fileNames[Fnames].cp_FileArr, buf_cp); //更新目录
strcpy(fileNames[Fnames].pa_FileArr, buf_pa); //更新目录.
fileNames[Fnames].p = fileName.p;
fileNames[Fnames].pool = fileName.pool;
add_task(fileNames[Fnames].pool, cpfile, (void*)&fileNames[Fnames]);
fileNames[Fnames].dir = opendir(fileNames[Fnames].cp_FileArr);//进入文件夹
Tast(fileNames[Fnames]);//调用自己
Tast(fileName);//回溯后继续判断是文件夹还是普通文件
}
else if(fileName.p->d_type == DT_REG)//如果是普通文件
{
Fnames++;
strcpy(fileNames[Fnames].cp_FileArr, buf_cp); //更新目录
strcpy(fileNames[Fnames].pa_FileArr, buf_pa); //更新目录.
fileNames[Fnames].p = fileName.p; //传参
fileNames[Fnames].pool = fileName.pool; //传参
bool ret = add_task(fileName.pool, cpfile1, (void*)&fileNames[Fnames]);//添加任务
Tast(fileName);//递归调用
}
}
}
int main(int argv, char **argc)
{
pthread_mutex_init(&g_mutex_cp, NULL);
filename_t fileName;
strcpy(fileName.cp_FileArr, argc[1]);
strcpy(fileName.pa_FileArr, argc[2]);
fileName.pool = malloc(sizeof(*fileName.pool));//创建线程池
fileName.dir = opendir(fileName.cp_FileArr);
init_pool(fileName.pool,20);
Tast(fileName);
destroy_pool(fileName.pool);
free(fileName.pool);
}