Linux环境下,利用线程池,可实现文件与文件绝对/相对路径的拷贝。可实现目录与目录绝对/相对路径的拷贝。

基于线程池的目录拷贝

可实现文件与文件绝对/相对路径的拷贝
可实现目录与目录绝对/相对路径的拷贝
具体实现代码如下:

//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

浅浅分享一下,记录一下!

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值