简介
在Linux下使用线程池复制文件下的内容比较快,所以就没有所以了。
代码
头文件
#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<dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.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;
/* data */
};
typedef struct thread_pool
{
pthread_mutex_t lock;
pthread_cond_t cond;
bool shutdown;
struct task *task_list;
pthread_t *tids;
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
线程池方法文件
#include"thread_pool.h"
//线程中断处理函数函数
void handler(void *arg)
{
printf("[%u] is ended.\n", (unsigned)pthread_self());//获取线程id
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==true)
{
pthread_mutex_unlock(&pool->lock);
pthread_exit(NULL);
}
//第三种情况:若是有任务进入线程池则调用线程
//把任务链表的第一个任务拆出来执行
p = pool->task_list->next;
pool->task_list->next = p->next;
p->next = NULL;
pool->waiting_tasks--;
//任务拿出完毕,互斥锁解除
pthread_mutex_unlock(&pool->lock);
//结束注册中断函数
pthread_cleanup_pop(0);
//防止线程执行过程中突然被取消,此时还应该把线程取消状态置为disable
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
//执行线程函数
(p->do_task)(p->arg);
//函数执行完毕,把线程取消状态置为enable
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);
//把shutdown标志位置为false
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("线程链表或者任务链表申请内存失败");
return false;
}
//初始化线程池内的属性
pool->task_list->next = NULL;
pool->waiting_tasks = 0;
//活跃线程数等于初始化的数目
pool->active_threads = threads_number;
//开始创建初始化所需要的线程
for (int i = 0; i < pool->active_threads; i++)
{
if(pthread_create(&(pool->tids[i]),NULL,routine,(void*)pool)!=0){
perror("创建线程失败");
}
}
//创建成功,返回true
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("申请新任务节点失败");
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>=MAX_WAITING_TASKS)
{
//消除互斥锁
pthread_mutex_unlock(&pool->lock);
//打印出错误
fprintf(stderr, "任务太多啦\n");
//释放掉新任务指针
free(new_task);
return false;
}
//新建任务链表指针
struct task *temp = pool->task_list;
//遍历任务链表到最后一个然后插到最后
while (temp->next!=NULL)
{
temp = temp->next;
}
temp->next = new_task;
//当前等待的线程加一
pool->waiting_tasks++;
//解除互斥锁
pthread_mutex_unlock(&pool->lock);
//发送一个条件等待的线程信号,解锁一个条件等待的线程
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++;
}
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 - remaining_threads;
//不可让仍存在的线程小于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;
}
if (i == pool->active_threads - 1)
return -1;
else
{
pool->active_threads = i + 1;
return i + 1;
}
}
//线程池销毁方法
bool destory_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]);
}
}
// 3, free memories
free(pool->task_list);
free(pool->tids);
free(pool);
return true;
}
线程池的调用和读取相应目录下的普通文件的方法
#include"thread_pool.h"
char new_dir[1024] = {0};
struct thread_pool *pool;
struct file
{
char old_file[2048];
char new_file[2048];
};
void*mycp(void *arg)
{
//指向结构体的首地址
struct file *p = (struct file *)arg;
//1.打开源文件
int fd = open(p->old_file, O_RDWR);
if(fd<0)
{
perror("打开源文件失败");
return NULL;
}
//2.创建新文件
int new_fd = open(p->new_file, O_RDWR | O_CREAT | O_TRUNC, 0777);
if(fd<0)
{
perror("创建新文件失败");
return NULL;
}
char buf[4096] = {0};
while (1)
{
//读取源文件数据
int size = read(fd, buf, 4096);
if(size<=0)
{
printf("拷贝完毕\n");
break;
}
//把读到的数据写入文件中
write(new_fd, buf, size);
}
close(fd);
close(new_fd);
}
//遍历目录中的所有文件名
char *Dir_traversal(char* dir)
{
//1.打开目录
DIR *dp = opendir(dir);
if(dp==NULL)
{
perror("打开目录失败");
}
while(1)
{
//读取目录中的所有文件名
struct dirent *msg = readdir(dp);
if(msg==NULL)
{
printf("读取目录完毕\n");
break;
}
if(msg->d_type==DT_REG)
{
//进行路径的拼凑
char old_path[2048] = {0};
char new_path[2048] = {0};
sprintf(old_path, "%s/%s", dir, msg->d_name); // test/main.c new_test/main.c
sprintf(new_path, "%s/%s", new_dir, msg->d_name);
printf("old_path=%s,new_path=%s\n", old_path, new_path);
struct file path;
strcpy(path.new_file, new_path);
strcpy(path.old_file, old_path);
//把任务添加到线程池 中
add_task(pool, mycp, (void *)&path);
}
}
//关闭目录
closedir(dp);
}
//cpdir 原目录名称 新目录名称
int main(int argc,char*argv[])
{
if(argc!=3)
{
printf("出入参数有误\n");
return -1;
}
//新建线程结构体
pool = malloc(sizeof(struct thread_pool));
//进行初始化
init_pool(pool, 10);
//新建一个目录
mkdir(argv[2], 0777);
//拷贝目录名
strcpy(new_dir, argv[2]);
//进行目录的拷贝
Dir_traversal(argv[1]);
}
最后附带上opendir详解