版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/s564200489/article/details/50538781
用Linux C完成shall命令cp的实现
在复制大量文件时,当遇到大量的或较大的文件时,使用单进程单线程进行文件复制效率比较低下,而使用线程池能很好的提高效率。
思路:
1、初始化线程池
2、如果需要复制文件则直接复制,如果需要复制文件夹则往下
3、遍历文件夹,复制内容
4、复制内容任务加入任务链表
线程池
线程池结构体
struct thread_pool
{
pthread_mutex_t mutex;//互斥锁
pthread_cond_t cond;//条件变量
int thread_num;//线程池中线程的数量
pthread_t *t;//每个线程的ID
struct task *head;//任务链表头
int cur_queue_size;//任务节点数
};
任务结构体
struct task
{
void *(*p)(struct tem *);//函数指针
struct tem *arg;//参数实参
struct task *next;//下一个任务的地址
};
在此任务链表为单向链表
主程序
#include "mycp.h"
int all_pthread_done = 0;
int main (int argc ,char **argv)
{
struct stat st;
pool_init(4);//初始化线程池
printf("init pool\n");
sleep(1);
stat(argv[1],&st);
struct tem t;//因为线程函数只能传入一个参数所以定义tem结构体包含源目录与目的目录
t.t_s = argv[1];
t.t_o = argv[2];
if (S_ISDIR(st.st_mode))//判断是否为目录
show_dir(argv[1],argv[2]);
else//为文件的话直接复制
{
copy_file(t);
}
all_pthread_done = 1;//告诉子线程所有任务添加完成
printf("finsh!!\n");
pthread_cond_broadcast(&(pool->cond));//唤醒在等待的线程
int i;
for(i=0;i<pool->thread_num;i++)
pthread_join(pool->t[i],NULL);//等待所有线程退出
printf("end\n");
pool_del();//回收线程等
return 0;
}
函数
#include "mycp.h"
extern int all_pthread_done ;
int already_get_tem = 0;
void pool_add_task(void *(*pr)(struct tem *),struct tem arg) //添加任务
{
struct task *newtask=malloc(sizeof(struct task));//创建,初始化任务
newtask->p = pr;
newtask->arg = arg;
newtask->next = NULL;
pthread_mutex_lock(&(pool->mutex));//上锁
printf("add task ing cp %s to %s\n",arg.t_s,arg.t_o );
//把newtask节点增加到任务链表尾。
struct task *temp = NULL;
if(pool->head==NULL)
pool->head = newtask;
else
{
temp = pool->head;
pool->head = newtask;
newtask->next = temp;
}
printf("add task fin cp %s to %s\n",newtask->arg.t_s,newtask->arg.t_o );
pool->cur_queue_size++;//任务增加一个
pthread_mutex_unlock(&(pool->mutex));
pthread_cond_signal(&(pool->cond));//告诉子线程任务添加完毕
printf("add task successful!!\n");
}
void *f(void *reg) //子线程
{
struct task *wh;
while(1)
{
pthread_mutex_lock(&(pool->mutex));
printf("wait for task\n");
while((pool->cur_queue_size==0)&&(all_pthread_done==0))//等待任务
pthread_cond_wait(&(pool->cond),&(pool->mutex));
if ((pool->cur_queue_size==0)&&(all_pthread_done==1))//如果没有任务切主线程添加任务完毕则退出
{
pthread_mutex_unlock(&(pool->mutex));
printf("pthread exit\n");
pthread_exit(0);
}
wh = pool->head; // 将任务从任务列表中取出
pool->head = wh->next;
pool->cur_queue_size--;
printf("get the task %s to %s\n", wh->arg.t_s,wh->arg.t_o);
pthread_mutex_unlock(&(pool->mutex));//读取完节点后解锁
(*(wh->p))(&(wh->arg));//执行任务
printf("copy finsh\n");
free(wh);//释放任务
}
}
void pool_init(int num)
{
pool = (struct thread_pool *)malloc(sizeof(struct thread_pool));//初始化线程池
pthread_mutex_init(&(pool->mutex),NULL);//初始化互斥锁
pthread_cond_init(&(pool->cond),NULL);//初始化条件变量
pool->thread_num=num;
pool->head=NULL;
pool->cur_queue_size=0;
pool->t = malloc(sizeof(pthread_t)*num);//建立数组,元素有num个
int i;
for(i=0;i<pool->thread_num;i++)
pthread_create(&(pool->t[i]),NULL,f,&i);//建立三个线程,线程号为pool->t
}
char * arr(char *frr,char *crr)//
{
int i = strlen(crr);
int j = strlen(frr);
char *a = malloc(sizeof(char)*(i+j+1+1));
sprintf(a,"%s/%s",frr,crr);
printf("arr a = %s\n", a);
return a;
}
char * arr_file(char *frr,char *crr)
{
int i = strlen(crr);
int j = strlen(frr);
char *a = malloc(sizeof(char)*(i+j+1+1));
if (frr[strlen(frr)]=='/')
sprintf(a,"%s%s",frr,crr);
else
sprintf(a,"%s/%s",frr,crr);
printf("arr_file a: %s\n", a);
return a;
}
char *arr_m(char *mdir,char *pdir)
{
if (mdir[0]=='.')
{
int i = 0,j;
j = strlen(mdir)+1;
printf("star %d j = %d, %c \n", i,j,mdir[0]);
sleep(1);
while(i < j)
{
sleep(1);
mdir[i] = mdir[++i];
printf("%d\n",i );
}
}
char *a = malloc(sizeof(char)*(strlen(mdir)+strlen(pdir)+1));
sprintf(a,"%s%s",pdir,mdir);
printf("arr_m a = %s\n", a);
sleep(3);
return a;
}
void * copy(struct tem *te)
{
printf("copying %s ..to.. %s\n", te->t_s,te->t_o);
int fd1 ,fd2,i=1024;
fd1 = open(te->t_s,O_RDONLY);
char buf[1024];
fd2 = open(te->t_o,O_RDWR|O_CREAT , 0777);
while(i == 1024)
{
i = read(fd1,buf,1024);
write(fd2,buf,i);
}
free(te->t_s);
free(te->t_o);
}
void copy_file(struct tem te)
{
printf("%s to %s\n",te.t_s,te.t_o );
char *c = malloc(sizeof(char)*(strlen(te.t_o)+1));
strcpy(c,te.t_o);
printf("c = %s\n", c);
int i ;
for (i = strlen(te.t_o);c[i]!='/';i--);
c[i] = '\0';
mkdir(c,0777);
int fd1 ,fd2;
i=1024;
fd1 = open(te.t_s,O_RDONLY);
char buf[1024];
fd2 = open(te.t_o,O_RDWR|O_CREAT , 0777);
while(i == 1024)
{
i = read(fd1,buf,1024);
write(fd2,buf,i);
}
free(C);
}
void show_dir(char *mdir,char *pdir)//遍历目录 ./123 ./456 ./123/555 ./456/555
{
char *temp,*temp2;
struct dirent * da;
struct tem tem;
DIR * dir = NULL;
printf("mkdiring pdir %s ...\n", pdir);
dir = opendir(mdir);
if(mkdir(pdir,0777)==-1)//先创建目的目录 ./456 ./456/555
{
printf("dir is already exists\n");
}
sleep(1);
while(da = readdir(dir))
{
if(da->d_name[0]=='.')
continue;
if((int)da->d_type==4)//判断原目录下的文件是目录还是普通文件 ./123/555
{
temp = arr(mdir,da->d_name);//得到完整的目录路径 ./123/555
temp2 = arr(pdir,da->d_name);//得到完整的目的目录路径./456/555
show_dir(temp,temp2);
free(temp);
free(temp2);
}else
{
tem.t_s = arr_file(mdir,da->d_name);//得到完整的原文件路径
tem.t_o = arr_file(pdir,da->d_name);//得到完整的目的文件路径
pool_add_task(copy,tem);//添加copy任务
//copy(&tem); //使用线程去做
}
}
closedir(dir);
}
void pool_del(void)
{
pthread_mutex_destroy(&(pool->mutex));
pthread_cond_destroy(&(pool->cond));
free(pool->t);
free(pool);
}
mycp.h
#ifndef _MYCP_H_
#define _MYCP_H_
#include <stdio.h>
#include <pthread.h>
#include <sys/types.h>
#include <dirent.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
struct tem
{
char *t_s;
char *t_o;
};
struct task
{
void *(*p)(struct tem *);
struct tem arg;//参数实参
struct task *next;
};
struct thread_pool
{
pthread_mutex_t mutex;
pthread_cond_t cond;
int thread_num;
pthread_t *t;
struct task *head;
int cur_queue_size;//任务节点数
};
struct thread_pool *pool;
void pool_add_task(void *(*pr)(struct tem *),struct tem arg); //增加任务
void *f(void *reg); //子线程
void pool_init(int num);
void pool_del(void);
void * copy(struct tem *te);
void show_dir(char *mdir,char *pdir);
char *arr_m(char *mdir,char *pdir);
char * arr_file(char *frr,char *crr);
char * arr(char *frr,char *crr);
void copy_file(struct tem te);
#endif