基于线程池的目录拷贝
可实现文件与文件绝对/相对路径的拷贝
可实现目录与目录绝对/相对路径的拷贝
具体实现代码如下:
//main.c
#include "threadpool.h"
#include <unistd.h>
#include <strings.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <dirent.h>
void copyfile(int fd1, int fd2)
{
char buf[1024];
int readdata, writedata;
char *tmp;
while (1)
{
while ((readdata = read(fd1, buf, 1024)) == -1 && errno == EINTR)
; //防止中断信号引起的误判
if (readdata == -1)
{
perror("read file faild");
break;
}
if (readdata == 0)
break;
tmp = buf;
while (readdata > 0)
{
while ((writedata = write(fd2, tmp, readdata)) == -1 && errno == EINTR)
;
if (writedata <= 0)
{
perror("write file faild!");
break;
}
readdata -= writedata;
tmp += writedata;
} //确保准确读完readdata个字节的数据
}
}
void *copytask(void *arg)
{
int fd1 = ((int *)arg)[0];
int fd2 = ((int *)arg)[1];
copyfile(fd1, fd2);
return NULL;
}
void copydir(thread_pool *pool, char *dir1, char *dir2)
{
DIR *dp = opendir(dir1);
struct dirent *ep;
struct stat info; //为了判定文件类型做准备,同时准备好目录中的目录做嵌套操作
int fd[2];
while (1)
{
ep = readdir(dp);
if (ep == NULL)
break; //读取完目录项后退出循环
if (ep->d_name[0] == '.')//过滤掉.和..目录项
continue;
chdir(dir1); //进入目录,为获取文件信息做准备
bzero(&info, sizeof(info));
stat(ep->d_name, &info); //获取文件信息
if (S_ISREG(info.st_mode)) //判断文件类型为普通文件的拓展宏
{
chdir(dir1);
fd[0] = open(ep->d_name, O_RDONLY);
chdir(dir2);
fd[1] = open(ep->d_name, O_WRONLY | O_CREAT | O_TRUNC, 0644); //进入待复制的目录,并创建待复制的文件
add_task(pool, copytask, (void *)fd); //进行复制操作
}
else if (S_ISDIR(info.st_mode)) //判断文件类型为目录文件的拓展宏
{
chdir(dir1); //进入源目录
char path1[100] = {0}; //准备好存放路径的缓冲区
chdir(ep->d_name); //进入源目录的子目录
getcwd(path1, 100); //获取当前路径即子目录路径,存入到path1
chdir(dir2);
char path2[100] = {0};
mkdir(ep->d_name, 0777);
chdir(ep->d_name);
getcwd(path2, 100);
copydir(pool,path1, path2); //嵌套递归调用
}
else
{
printf("跳过无法拷贝的其他文件:%s\n", ep->d_name);
}
}
}
int main(int argc, char const *argv[])
{
thread_pool *pool = calloc(1, sizeof(thread_pool)); //用线程池实现目录或文件的复制
if (pool == NULL)
{
perror("request pool faild!");
exit(0);
}
unsigned int threads_number = 2;
if (!init_pool(pool, threads_number))
{
perror("initpool faild!");
exit(0);
}
if (argc != 3)
{
printf("正确用法:<./main><原文件><生成的目标文件>");
exit(0);
}
struct stat info;
bzero(&info, sizeof(info));
stat(argv[1], &info);
int fd[2]; //便于后续传参给线程任务函数
if (S_ISREG(info.st_mode))
{
fd[0] = open(argv[1], O_RDONLY);
fd[1] = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, 0644);
add_task(pool, copytask, (void *)fd);
}
else if (S_ISDIR(info.st_mode))
{
char oripath[100] = {0};
getcwd(oripath, 100);
chdir(argv[1]);
char path1[100] = {0};
getcwd(path1, 100);
chdir(oripath);
mkdir(argv[2], 0777);
char path2[100] = {0};
chdir(argv[2]);
getcwd(path2, 100);
copydir(pool, path1, path2);
}
else
{
printf("sorry!该文件:%s无法拷贝\n", argv[1]);
}
detory_pool(pool);
return 0;
}
//threadpool.c
#include "threadpool.h"
//本次并未用到增加和删除线程,写出来只是为了丰富对于线程池功能的描述
bool init_pool(thread_pool *pool, unsigned int threads_number)//初始化线程池
{
pthread_mutex_init(&pool->lock, NULL);//初始化互斥锁
pthread_cond_init(&pool->cond, NULL);//初始化条件变量
pool->shutdown = false;//初始化线程池开关标志位,开启线程池
pool->max_waiting_tasks = 1000;//设置最大现存任务数为1000
pool->task_list = calloc(1, sizeof(struct task));//初始化任务链表
if (pool->task_list == NULL)
{
perror("request task_list faild!");
return false;
}
pool->task_list->next = NULL;//初始化头结点指向
pool->tids = calloc(pool->max_waiting_tasks, sizeof(pthread_t));//初始化线程id群组
if (pool->tids == NULL)
{
perror("request tids faild!");
return false;
}
pool->waiting_tasks = 0;//初始化现存任务数
pool->active_threads = threads_number;
for (int i = 0; i < threads_number; i++)
{
if (pthread_create((&(pool->tids[i])), NULL, routine, (void *)pool) != 0)
{
perror("creat threads faild!");
return false;
}
}//建立线程
return true;
}
bool add_task(thread_pool *pool, void *(*do_task)(void *arg), void *arg)//增加任务
{
struct task *new_task = calloc(1, sizeof(struct task));
if (new_task == NULL)
{
perror("requst new_task faild");
return false;
}
new_task->do_task = do_task;
new_task->arg = arg;
new_task->next = NULL;
pthread_mutex_lock(&pool->lock);//加锁
if (pool->waiting_tasks >= pool->max_waiting_tasks)
{
pthread_mutex_unlock(&pool->lock);
printf("tasks full!\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++;
pthread_mutex_unlock(&pool->lock);//解锁
pthread_cond_signal(&pool->cond); //唤醒线程,再次判定是否有条件执行
return true;
}
void handler(void *arg)//句柄函数,相当于遗言,防止函数在加锁执行过程中异常退出,导致死锁
{
pthread_mutex_unlock((pthread_mutex_t *)arg);
}
void *routine(void *arg)//遍历线程
{
thread_pool *pool = (thread_pool *)arg;
struct task *p;
while (1)
{
pthread_cleanup_push(handler, (void *)(&pool->lock)); //压入清理函数栈,防止函数异常退出时形成死锁
pthread_mutex_lock(&pool->lock);
while (pool->waiting_tasks == 0 && !pool->shutdown)
{
pthread_cond_wait(&pool->cond, &pool->lock); //解锁并等待
}
if (pool->waiting_tasks == 0 && pool->shutdown)
{
pthread_mutex_unlock(&pool->lock);
pthread_exit(NULL);
}
p = pool->task_list->next;
pool->task_list->next = p->next;
pool->waiting_tasks--;
pthread_mutex_unlock(&pool->lock);
pthread_cleanup_pop(0); //弹出清理栈并且不执行该函数栈
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); //设置线程不能响应取消信号
(p->do_task)(p->arg); //执行p节点函数
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); //设置线程能响应取消信号
free(p);
}
pthread_exit(NULL);
}
int add_thread(thread_pool *pool, unsigned additional_threads)//增加线程
{
if (additional_threads == 0)
return 0;
unsigned total_threads = pool->active_threads + additional_threads;
int actual_increment = 0; //记录真正增加的线程数
for (int i = pool->active_threads; i < total_threads && i < pool->max_waiting_tasks; i++)
{
if (pthread_create(&((pool->tids)[i]), NULL, routine, (void *)pool) != 0)
{
perror("add threads faild!");
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)
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;
}
if (i == pool->active_threads - 1) // i未改变,删除线程失败(判定)
return -1;
else
{
pool->active_threads = i + 1; //当前实际线程数
return pool->active_threads;
}
}
bool detory_pool(thread_pool *pool)//摧毁线程池
{
pool->shutdown = true;
pthread_cond_broadcast(&pool->cond); //此时线程池已关闭,唤醒所有线程,让其运行后退出
for (int 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)); //打印出具体出错的线程ID,和错误类型
}
else
printf("[%u] is joined\n", (unsigned)pool->tids[i]);
}
free(pool->task_list);
free(pool->tids);
free(pool);
return true;
}
//threadpool.h
#ifndef _THREADPOOL_H
#define _THREADPOOL_H
#include <pthread.h>
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
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 *arg);
void handler(void *arg);
void *routine(void *arg);
int add_thread(thread_pool *pool,unsigned additional_threads);
int remove_thread(thread_pool *pool,unsigned int removing_threads);
bool detory_pool(thread_pool *pool);
#endif
//Makefile
main:main.c threadpool.c
gcc main.c threadpool.c -o main -lpthread
浅浅分享一下,记录一下!