线 程 池

一. 线程池原理

线程池是一种多线程的处理方式,处理方法是将“生产者”线程提出的任务添加到“任务队列”,然后创建一些线程自动去完成“任务队列”上面的任务,可以降低频繁创建和销毁线程带来的实际开销

线程池技术思路如下:
"任务队列"是一个共享资源,“互斥访问”

        一般采用预创建线程技术,也就是在应用启动的时候就创建一定数量的线程
        线程固定的执行一个“任务调配函数”,当“任务队列”没有任务的时候,线程自动的休眠(等待一个条件),当任务到来的时候,被唤醒,执行任务
        线程完成任务后不会被销毁,而是自动的执行任务队列的下一个任务
        当任务太多的时候,增加一些线程数量,当任务太少的时候,销毁一些线程

二. 代码实现

threadpool.h
#ifndef __THREADPOOL_H__
#define __THREADPOOL_H__

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#define info_err(format, ...) { \
	printf(format, __VA_ARGS__); \
	perror(""); \
}

// 线程处理函数
typedef void (*threadHand_t) (void *);

// 事件队列结构体
typedef struct task {
	threadHand_t func;
	void *arg;
} Task;

// 线程池结构体
typedef struct threadpool {
	// 事件队列
	Task *taskQueue;  // 顺序队列
	int QSize;	  	  // 队列的最大元素个数
	int QNum;		  // 队列中的事件个数
	int QFront;		  // 队头
	int QRear;		  // 队尾	
	
	// 线程池信息
	pthread_t managerID;	// 管理者线程ID
	pthread_t *threadID;	// 消费者线程ID
	int MAXThreadNum;		// 最大线程数量
	int MINThreadNum;		// 最小线程数量
	int busyThreadNum;		// 工作的线程		
	int liveThreadNum;		// 活着的线程
	int exitThreadNum;		// 需要销毁的线程数量
	
	pthread_mutex_t mutexPool;	// 整个线程池的线程锁
	pthread_mutex_t mutexBusy;	// 忙线程的线程锁
	
	pthread_cond_t notFull;	 // 事件队列不满
	pthread_cond_t notEmpty; // 事件队列非空
	
	// 线程池状态  0 表示使用  1表示销毁
	int shutdown;	
} ThreadPool;

// 创建线程池 并初始化
ThreadPool* threadPoolInit(int min, int max, int size);

// 销毁线程池
int threadPoolDestroy(ThreadPool *pool);

// 给线程池 添加任务
void threadPoolAdd(ThreadPool *pool, threadHand_t func, void *arg);

// 获取线程池中 工作的线程个数
int threadPoolBusyNum(ThreadPool *pool);

// 获取线程池中 活着的线程个数
int threadPoolAliveNum(ThreadPool *pool);

// 管理线程
void *manager(void *arg);

// 工作线程
void* work(void *arg);

// 线程退出函数
void threadExit(ThreadPool *pool);

#endif
threadpool.c
#include "threadpool.h"

const int CHANGENUM = 2; // 一次最多增加的消费者线程数量

// 创建线程池 并初始化
/*
	min: 最小线程数--核心线程数量 
	max: 最大线程数
	size: 任务队列的最大元素个数
*/
ThreadPool* threadPoolInit(int min, int max, int size) {
	// 定义一个线程池结构体指针
	ThreadPool *threadPool = NULL;
	do {
		// 给线程池空间分配
		threadPool = malloc(sizeof(ThreadPool));
		if (threadPool == NULL) {
			perror("threadPool malloc fail");
			break;
		}

		/* 线程池事件队列初始化 */
		threadPool->taskQueue = malloc(sizeof(Task) * size);
		if (threadPool->taskQueue == NULL) {
			perror("taskQueue malloc fail");
			break;
		}
		threadPool->QSize = size; // 队列的最大元素个数
		threadPool->QNum = 0; // 队列中的事件个数
		threadPool->QFront = threadPool->QRear = 0; // 对头、队尾


		/* 线程池信息初始化 */
		threadPool->MAXThreadNum = max; // 最大线程数量
		threadPool->MINThreadNum = min; // 最小线程数量
		// 消费者线程ID
		threadPool->threadID = malloc(sizeof(threadPool->threadID) * max);
		if (threadPool->threadID == NULL) {
			perror("threadID malloc fail");		
			break;
		}
		// 将消费者线程ID全部初始化为0
		memset(threadPool->threadID, 0, sizeof(threadPool->threadID) * max);

		threadPool->liveThreadNum = min; // 活着的线程
		threadPool->busyThreadNum = 0; // 工作的线程
		threadPool->exitThreadNum = 0; // 需要销毁的线程数量
	
		if (pthread_mutex_init(&threadPool->mutexPool, NULL) != 0 ||
			pthread_mutex_init(&threadPool->mutexBusy, NULL) != 0 ||
			pthread_cond_init(&threadPool->notFull, NULL) != 0 ||
			pthread_cond_init(&threadPool->notEmpty, NULL) != 0)
		{
			printf("mutex or cond fail\n");			
			break;
		}

		/* 线程池状态  0 表示使用  1表示销毁 */
		threadPool->shutdown = 0;
		
		// 创建一个管理者线程  管理者线程ID:threadPool->managerID
		pthread_create(&(threadPool->managerID), NULL, manager, threadPool);
		for (int i = 0; i < min; i++) {
			// 创建线程   线程池工作的最小线程
			pthread_create(&(threadPool->threadID[i]), NULL, work, threadPool);			
		}

		return threadPool;
	} while(0);

	if (threadPool && threadPool->threadID) {
		free(threadPool->threadID);
	}
	if (threadPool && threadPool->taskQueue) {
		free(threadPool->taskQueue);
	}
	if (threadPool) {
		free(threadPool);
	}
	return NULL;
}

// 销毁线程池
int threadPoolDestroy(ThreadPool *pool) {
	if (pool == NULL) {
        return -1;
    }

    // 关闭线程池
    pool->shutdown = 1;
    // 阻塞回收管理者线程
    pthread_join(pool->managerID, NULL);

    // 唤醒阻塞的消费者线程
    for (int i = 0; i < pool->liveThreadNum; i++) {
        pthread_cond_signal(&pool->notEmpty);
    }

    // 释放堆内存
    if (pool->taskQueue) {
        free(pool->taskQueue);
    }
    if (pool->threadID) {
        free(pool->threadID);
    }

    pthread_mutex_destroy(&pool->mutexPool);
    pthread_mutex_destroy(&pool->mutexBusy);
    pthread_cond_destroy(&pool->notEmpty);
    pthread_cond_destroy(&pool->notFull);

    free(pool);
    pool = NULL;

    return 0;
}

// 给线程池 添加任务
void threadPoolAdd(ThreadPool *pool, threadHand_t func, void *arg) {
	pthread_mutex_lock(&pool->mutexPool);

	// 当 队列满 且 不关闭线程池
    while (pool->QNum == pool->QSize && !pool->shutdown) {
        // 阻塞生产者线程 -- 拒绝策略
        pthread_cond_wait(&pool->notFull, &pool->mutexPool);
    }

    // 关闭线程池
    if (pool->shutdown) {
        pthread_mutex_unlock(&pool->mutexPool);
        return;
    }
    // 添加任务
    pool->taskQueue[pool->QRear].func = func;
    pool->taskQueue[pool->QRear].arg = arg;
    pool->QRear = (pool->QRear + 1) % pool->QSize;
    pool->QNum++;

    // 唤醒线程去执行任务
    pthread_cond_signal(&pool->notEmpty);
	info_err("%d\n", __LINE__);
    pthread_mutex_unlock(&pool->mutexPool);
}

// 获取线程池中 工作的线程个数
int threadPoolBusyNum(ThreadPool *pool) {
	pthread_mutex_lock(&pool->mutexBusy);
	
    int busyNum = pool->busyThreadNum;
	
    pthread_mutex_unlock(&pool->mutexBusy);
    return busyNum;
}

// 获取线程池中 活着的线程个数
int threadPoolAliveNum(ThreadPool *pool) {
	pthread_mutex_lock(&pool->mutexPool);
    int aliveNum = pool->liveThreadNum;
    pthread_mutex_unlock(&pool->mutexPool);
    return aliveNum;
}

// 管理线程
void* manager(void *arg) {
	ThreadPool *pool = (ThreadPool *)arg;

	while (!pool->shutdown) {
		// 每隔 3s 检测一次
		sleep(3);

		// 取出当前线程池中任务的数量 和 当前线程的数量
		pthread_mutex_lock(&pool->mutexPool);
		int QNum = pool->QNum; // 线程池任务数量
		int liveNum = pool->liveThreadNum; // 当前线程数量
		pthread_mutex_unlock(&pool->mutexPool);

		// 取出当前忙线程的个数
		pthread_mutex_lock(&pool->mutexBusy);
		int busyNum = pool->busyThreadNum;
		pthread_mutex_unlock(&pool->mutexBusy);

		// 添加线程 -- 任务的个数 > 存活的线程个数 && 存活的线程数 < 最大线程数
		if (QNum > liveNum && liveNum < pool->MAXThreadNum) {
			pthread_mutex_lock(&pool->mutexPool);
			int cnt = 0;
			for (int i = 0; i < pool->MAXThreadNum && cnt < CHANGENUM
				&& pool->liveThreadNum < pool->MAXThreadNum; i++)
			{
				if (pool->threadID[i] == 0) {
					pthread_create(&pool->threadID[i], NULL, work, pool);
					cnt++;
					pool->liveThreadNum++;
				}
			}
			pthread_mutex_unlock(&pool->mutexPool);
		}
		
		// 销毁线程  忙线程*2 < 存活的线程数 && 存活的线程 > 最小线程数
		if (busyNum * 2 < liveNum && liveNum > pool->MINThreadNum) {
			pthread_mutex_lock(&pool->mutexPool);
			pool->exitThreadNum = CHANGENUM;
			pthread_mutex_unlock(&pool->mutexPool);

			// 让工作的线程自杀
			for (int i = 0; i < CHANGENUM; i++) {
				pthread_cond_signal(&pool->notEmpty);
			}
		}
	}
	return NULL;
}

// 工作线程
void* work(void *arg) {
	ThreadPool *pool = (ThreadPool *)arg;

	while (1) {
		pthread_mutex_lock(&pool->mutexPool);

		// 当前的任务队列是否为空
		while (pool->QNum == 0 && !pool->shutdown) {
			// 阻塞工作线程
			pthread_cond_wait(&pool->notEmpty, &pool->mutexPool);

			// 判断是否需要 销毁线程
			if (pool->exitThreadNum > 0) {
				pool->exitThreadNum--;
				// 醒来之后 是上锁状态 线程退出之前不能带锁退出
				pthread_mutex_unlock(&pool->mutexPool);
				// 退出该工作线程
				threadExit(pool);		
			}
		}

		if (pool->shutdown) {
			pthread_mutex_unlock(&pool->mutexPool);
			// 退出该工作线程
			threadExit(pool);
		}

		// 从队列中取出一个任务
		Task task;
		task.func = pool->taskQueue[pool->QFront].func;
		task.arg = pool->taskQueue[pool->QFront].arg;

		// front++
		pool->QFront = (pool->QFront + 1) % pool->QSize;
		pool->QNum--;

		// 取出一个 尝试唤醒生产者线程
		pthread_cond_signal(&pool->notFull);

		// 解锁
		pthread_mutex_unlock(&pool->mutexPool);

		pthread_mutex_lock(&pool->mutexBusy);
		pool->busyThreadNum++;
		pthread_mutex_unlock(&pool->mutexBusy);

		// 函数指针,执行函数
		task.func(task.arg);
		free(task.arg);
		task.arg = NULL;

		pthread_mutex_lock(&pool->mutexBusy);
		pool->busyThreadNum--;
		pthread_mutex_unlock(&pool->mutexBusy);		
	}

	return NULL;
}

// 线程退出函数
void threadExit(ThreadPool *pool) {
	pthread_t tid = pthread_self();

	for (int i = 0; i < pool->MAXThreadNum; i++) {
		if (tid == pool->threadID[i]) {
			pool->threadID[i] = 0;
			printf("thread %ld exiting...\n", tid);
			break;
		}
	}
	pthread_exit(NULL);
}
main.c
#include "threadpool.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

void taskFunc(void *arg) {
	char *str = (char *)arg;
	printf("tid:%ld %s\n", pthread_self(), str);
	usleep(100000);
}

int main() {
	// 1. 初始化线程池
	ThreadPool *pool = threadPoolInit(3, 10, 50);

	// 2. 创建任务 -- 任务函数 、任务数据
	for (int i = 0; i < 100; i++) {
		char buf[20] = {0};
		sprintf(buf, "task %d", i);		
		char *str = malloc(strlen(buf) + 1 );
		strcpy(str, buf);
		threadPoolAdd(pool, taskFunc, str);
	}

	// 3. 等待任务结束
	sleep(10);

	// 4. 销毁线程池
	threadPoolDestroy(pool);
	
	return 0;
}

三. 练习—实现目录拷贝

threadpool.h
#ifndef __THREADPOOL_H__
#define __THREADPOOL_H__

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#define info_err(format, ...) { \
	printf(format, __VA_ARGS__); \
	perror(""); \
}

// 线程池头文件
// 任务队列结构体

// 线程处理函数
typedef void (*threadHand_t) (void *);

// 事件队列结构体
typedef struct task {
	threadHand_t func;
	void *arg;
} Task;

// 线程池结构体
typedef struct threadpool {
	// 事件队列
	Task *taskQueue;  // 顺序队列
	int QSize;	  	  // 队列的最大元素个数
	int QNum;		  // 队列中的事件个数
	int QFront;		  // 队头
	int QRear;		  // 队尾	
	
	// 线程池信息
	pthread_t managerID;	// 管理者线程ID
	pthread_t *threadID;	// 消费者线程ID
	int MAXThreadNum;		// 最大线程数量
	int MINThreadNum;		// 最小线程数量
	int busyThreadNum;		// 工作的线程		
	int liveThreadNum;		// 活着的线程
	int exitThreadNum;		// 需要销毁的线程数量
	
	pthread_mutex_t mutexPool;	// 整个线程池的线程锁
	pthread_mutex_t mutexBusy;	// 忙线程的线程锁
	
	pthread_cond_t notFull;	 // 事件队列不满
	pthread_cond_t notEmpty; // 事件队列非空
	
	// 线程池状态  0 表示使用  1表示销毁
	int shutdown;	
} ThreadPool;

// 创建线程池 并初始化
ThreadPool* threadPoolInit(int min, int max, int size);

// 销毁线程池
int threadPoolDestroy(ThreadPool *pool);

// 给线程池 添加任务
void threadPoolAdd(ThreadPool *pool, threadHand_t func, void *arg);

// 获取线程池中 工作的线程个数
int threadPoolBusyNum(ThreadPool *pool);

// 获取线程池中 活着的线程个数
int threadPoolAliveNum(ThreadPool *pool);

// 管理线程
void *manager(void *arg);

// 工作线程
void* work(void *arg);

// 线程退出函数
void threadExit(ThreadPool *pool);

#endif
threadpool.c
#include "threadpool.h"

const int CHANGENUM = 2; // 一次最多增加的消费者线程数量

// 创建线程池 并初始化
/*
	min: 最小线程数--核心线程数量 
	max: 最大线程数
	size: 任务队列的最大元素个数
*/
ThreadPool* threadPoolInit(int min, int max, int size) {
	// 定义一个线程池结构体指针
	ThreadPool *threadPool = NULL;
	do {
		// 给线程池空间分配
		threadPool = malloc(sizeof(ThreadPool));
		if (threadPool == NULL) {
			perror("threadPool malloc fail");
			break;
		}

		/* 线程池事件队列初始化 */
		threadPool->taskQueue = malloc(sizeof(Task) * size);
		if (threadPool->taskQueue == NULL) {
			perror("taskQueue malloc fail");
			break;
		}
		threadPool->QSize = size; // 队列的最大元素个数
		threadPool->QNum = 0; // 队列中的事件个数
		threadPool->QFront = threadPool->QRear = 0; // 对头、队尾


		/* 线程池信息初始化 */
		threadPool->MAXThreadNum = max; // 最大线程数量
		threadPool->MINThreadNum = min; // 最小线程数量
		// 消费者线程ID
		threadPool->threadID = malloc(sizeof(threadPool->threadID) * max);
		if (threadPool->threadID == NULL) {
			perror("threadID malloc fail");		
			break;
		}
		// 将消费者线程ID全部初始化为0
		memset(threadPool->threadID, 0, sizeof(threadPool->threadID) * max);

		threadPool->liveThreadNum = min; // 活着的线程
		threadPool->busyThreadNum = 0; // 工作的线程
		threadPool->exitThreadNum = 0; // 需要销毁的线程数量
	
		if (pthread_mutex_init(&threadPool->mutexPool, NULL) != 0 ||
			pthread_mutex_init(&threadPool->mutexBusy, NULL) != 0 ||
			pthread_cond_init(&threadPool->notFull, NULL) != 0 ||
			pthread_cond_init(&threadPool->notEmpty, NULL) != 0)
		{
			printf("mutex or cond fail\n");			
			break;
		}

		/* 线程池状态  0 表示使用  1表示销毁 */
		threadPool->shutdown = 0;
		
		// 创建一个管理者线程  管理者线程ID:threadPool->managerID
		pthread_create(&(threadPool->managerID), NULL, manager, threadPool);
		for (int i = 0; i < min; i++) {
			// 创建线程   线程池工作的最小线程
			pthread_create(&(threadPool->threadID[i]), NULL, work, threadPool);			
		}

		return threadPool;
	} while(0);

	if (threadPool && threadPool->threadID) {
		free(threadPool->threadID);
	}
	if (threadPool && threadPool->taskQueue) {
		free(threadPool->taskQueue);
	}
	if (threadPool) {
		free(threadPool);
	}
	return NULL;
}

// 销毁线程池
int threadPoolDestroy(ThreadPool *pool) {
	if (pool == NULL) {
        return -1;
    }

    // 关闭线程池
    pool->shutdown = 1;
    // 阻塞回收管理者线程
    pthread_join(pool->managerID, NULL);

    // 唤醒阻塞的消费者线程
    for (int i = 0; i < pool->liveThreadNum; i++) {
        pthread_cond_signal(&pool->notEmpty);
    }

    // 释放堆内存
    if (pool->taskQueue) {
        free(pool->taskQueue);
    }
    if (pool->threadID) {
        free(pool->threadID);
    }

    pthread_mutex_destroy(&pool->mutexPool);
    pthread_mutex_destroy(&pool->mutexBusy);
    pthread_cond_destroy(&pool->notEmpty);
    pthread_cond_destroy(&pool->notFull);

    free(pool);
    pool = NULL;

    return 0;
}

// 给线程池 添加任务
void threadPoolAdd(ThreadPool *pool, threadHand_t func, void *arg) {
	pthread_mutex_lock(&pool->mutexPool);

	// 当 队列满 且 不关闭线程池
    while (pool->QNum == pool->QSize && !pool->shutdown) {
        // 阻塞生产者线程 -- 拒绝策略
        pthread_cond_wait(&pool->notFull, &pool->mutexPool);
    }

    // 关闭线程池
    if (pool->shutdown) {
        pthread_mutex_unlock(&pool->mutexPool);
        return;
    }
    // 添加任务
    pool->taskQueue[pool->QRear].func = func;
    pool->taskQueue[pool->QRear].arg = arg;
    pool->QRear = (pool->QRear + 1) % pool->QSize;
    pool->QNum++;

    // 唤醒线程去执行任务
    pthread_cond_signal(&pool->notEmpty);
	info_err("%d\n", __LINE__);
    pthread_mutex_unlock(&pool->mutexPool);
}

// 获取线程池中 工作的线程个数
int threadPoolBusyNum(ThreadPool *pool) {
	pthread_mutex_lock(&pool->mutexBusy);
	
    int busyNum = pool->busyThreadNum;
	
    pthread_mutex_unlock(&pool->mutexBusy);
    return busyNum;
}

// 获取线程池中 活着的线程个数
int threadPoolAliveNum(ThreadPool *pool) {
	pthread_mutex_lock(&pool->mutexPool);
    int aliveNum = pool->liveThreadNum;
    pthread_mutex_unlock(&pool->mutexPool);
    return aliveNum;
}

// 管理线程
void* manager(void *arg) {
	ThreadPool *pool = (ThreadPool *)arg;

	while (!pool->shutdown) {
		// 每隔 3s 检测一次
		sleep(3);

		// 取出当前线程池中任务的数量 和 当前线程的数量
		pthread_mutex_lock(&pool->mutexPool);
		int QNum = pool->QNum; // 线程池任务数量
		int liveNum = pool->liveThreadNum; // 当前线程数量
		pthread_mutex_unlock(&pool->mutexPool);

		// 取出当前忙线程的个数
		pthread_mutex_lock(&pool->mutexBusy);
		int busyNum = pool->busyThreadNum;
		pthread_mutex_unlock(&pool->mutexBusy);

		// 添加线程 -- 任务的个数 > 存活的线程个数 && 存活的线程数 < 最大线程数
		if (QNum > liveNum && liveNum < pool->MAXThreadNum) {
			pthread_mutex_lock(&pool->mutexPool);
			int cnt = 0;
			for (int i = 0; i < pool->MAXThreadNum && cnt < CHANGENUM
				&& pool->liveThreadNum < pool->MAXThreadNum; i++)
			{
				if (pool->threadID[i] == 0) {
					pthread_create(&pool->threadID[i], NULL, work, pool);
					cnt++;
					pool->liveThreadNum++;
				}
			}
			pthread_mutex_unlock(&pool->mutexPool);
		}
		
		// 销毁线程  忙线程*2 < 存活的线程数 && 存活的线程 > 最小线程数
		if (busyNum * 2 < liveNum && liveNum > pool->MINThreadNum) {
			pthread_mutex_lock(&pool->mutexPool);
			pool->exitThreadNum = CHANGENUM;
			pthread_mutex_unlock(&pool->mutexPool);

			// 让工作的线程自杀
			for (int i = 0; i < CHANGENUM; i++) {
				pthread_cond_signal(&pool->notEmpty);
			}
		}
	}
	return NULL;
}

// 工作线程
void* work(void *arg) {
	ThreadPool *pool = (ThreadPool *)arg;

	while (1) {
		pthread_mutex_lock(&pool->mutexPool);

		// 当前的任务队列是否为空
		while (pool->QNum == 0 && !pool->shutdown) {
			// 阻塞工作线程
			pthread_cond_wait(&pool->notEmpty, &pool->mutexPool);

			// 判断是否需要 销毁线程
			if (pool->exitThreadNum > 0) {
				pool->exitThreadNum--;
				// 醒来之后 是上锁状态 线程退出之前不能带锁退出
				pthread_mutex_unlock(&pool->mutexPool);
				// 退出该工作线程
				threadExit(pool);		
			}
		}

		if (pool->shutdown) {
			pthread_mutex_unlock(&pool->mutexPool);
			// 退出该工作线程
			threadExit(pool);
		}

		// 从队列中取出一个任务
		Task task;
		task.func = pool->taskQueue[pool->QFront].func;
		task.arg = pool->taskQueue[pool->QFront].arg;

		// front++
		pool->QFront = (pool->QFront + 1) % pool->QSize;
		pool->QNum--;

		// 取出一个 尝试唤醒生产者线程
		pthread_cond_signal(&pool->notFull);

		// 解锁
		pthread_mutex_unlock(&pool->mutexPool);

		pthread_mutex_lock(&pool->mutexBusy);
		pool->busyThreadNum++;
		pthread_mutex_unlock(&pool->mutexBusy);

		// 函数指针,执行函数
		task.func(task.arg);
		free(task.arg);
		task.arg = NULL;

		pthread_mutex_lock(&pool->mutexBusy);
		pool->busyThreadNum--;
		pthread_mutex_unlock(&pool->mutexBusy);		
	}

	return NULL;
}

// 线程退出函数
void threadExit(ThreadPool *pool) {
	pthread_t tid = pthread_self();

	for (int i = 0; i < pool->MAXThreadNum; i++) {
		if (tid == pool->threadID[i]) {
			pool->threadID[i] = 0;
			printf("thread %ld exiting...\n", tid);
			break;
		}
	}
	pthread_exit(NULL);
}
cp_dir.h
#ifndef __CP_DIR_H__
#define __CP_DIR_H__    

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <dirent.h>

#define MAXPATHNAMESIZE 512

// 拷贝文件
void taskFunc(void *arg);

// 产生任务放入线程池
void cp_dir(ThreadPool *pool, char *dir_src, char *dir_dest);

#endif
cp_dir.c
#include "cp_dir.h"
#include "threadpool.h"

// 拷贝文件
void taskFunc(void *arg) {
	char **pathname = (char **)arg;

    int fd1 = open(pathname[0], O_RDWR);
    if (fd1 == -1) {
        perror("open fd1 failed");
        return;
    }
    int fd2 = open(pathname[1], O_RDWR | O_CREAT, 0777);
    if (fd2 == -1) {
        perror("open fd2 failed");
        close(fd1);
        return;
    }

	// 不断的读取1.txt的内容,把读取到的内容写入到2.txt
    char buf[50] = {0};
    while (1) {
        ssize_t r = read(fd1, buf, 50);
        if (0 == r) {
            // 读取完毕
            break;
        } else if (-1 == r) {
            perror("read fd1 failed");
            break;
        }
        ssize_t w = write(fd2, buf, r);
        if (-1 == w) {
            perror("write fd2 failed");
            break;
        }
    }
    // 关闭两个文件
    close(fd1);
    close(fd2);
}

// 产生任务放入线程池
void cp_dir(ThreadPool *pool, char *dir_src, char *dir_dest) {
	// 所有的路径都使用绝对路径
	char abs_cur[MAXPATHNAMESIZE] = {0}; // 保存当前的工作路径
	char abs_src[MAXPATHNAMESIZE] = {0}; // 源目录的绝对路径
	char abs_dest[MAXPATHNAMESIZE] = {0}; // 目标目录的绝对路径

	// 获取当前的工作路径
	getcwd(abs_cur, MAXPATHNAMESIZE);
	// 获取源目录的绝对路径
	chdir(dir_src);
	getcwd(abs_src, MAXPATHNAMESIZE);
	
	// 获取目标目录的绝对路径
	chdir(abs_cur); // 切换到工作路径
	mkdir(dir_dest, 0777); // 创建目标目录
	chdir(dir_dest);
	getcwd(abs_dest, MAXPATHNAMESIZE);
	
    // 回到当前的工作路径
    chdir(abs_cur);
	
	// 打开abs_src指定的目录
	DIR *dirp = opendir(dir_src);
	
	// 读源目录的目录项
	struct dirent *dp = NULL;
	
	while (dp = readdir(dirp)) {
		// 排除当前目录下的./..
        if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) {
            continue;
        }
        char src_name[MAXPATHNAMESIZE] = {0};
        sprintf(src_name, "%s/%s", abs_src, dp->d_name);
        char dest_name[MAXPATHNAMESIZE] = {0};
        sprintf(dest_name, "%s/%s", abs_dest, dp->d_name);

        struct stat st;
        int ret = stat(src_name, &st);
        if (ret == -1) {
            perror("stat failed");
            return; 
        }
        if (S_ISDIR(st.st_mode)) { 
            // 递归的查找子目录
            cp_dir(pool, src_name, dest_name);
        } else if (S_ISREG(st.st_mode)) {
            char **pathname = malloc(sizeof(char*) * 2); // 传入线程函数的文件描述符
            for (int i = 0; i < 2; i++) {
                pathname[i] = malloc(sizeof(char) * MAXPATHNAMESIZE);
            }
            strcpy(pathname[0], src_name);
            strcpy(pathname[1], dest_name);
			threadPoolAdd(pool, taskFunc, pathname);
		}
	}
}
main.c
#include "threadpool.h"
#include "cp_dir.h"

int main(int argc, char *argv[]) {
    if (argc != 3) {
        printf("please input: ./a.out dir1 dir2\n");
        return -1;
    }
    
	// 1. 初始化线程池
	ThreadPool *pool = threadPoolInit(3, 10, 50);

	// 2. 创建任务 -- 任务函数 、任务数据
	cp_dir(pool, argv[1], argv[2]);

	// 3. 等待任务结束
	sleep(10);

	// 4. 销毁线程池
	threadPoolDestroy(pool);
	
	return 0;
}
  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值