使用线程池实现复制当前目录下所有文件【简单版】

简介

在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详解


在这里插入图片描述

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值