嵌入式Linux系统编程-》线程池+面试题+源码活动地址:毕业季·进击的技术er
- 1. 工程背景
- 2. 逻辑框架
- 3. 线程组织
- 4. 任务组织
- 5. 示例代码
- main.c
- pthread_cleanup.c
- thread_pool.h
- thread_pool.c
- Makefile
- 6.线程池接口文档
- 10.面试题
- threadpool.h
- threadpool.c
- copy.c
- main.c
- Makefile
- 结束篇总结
Linux系统编程告一段落
1. 工程背景
考虑这么一个情况:为应对某场景的实际需求,要在程序中创建大量线程,并且这些线程的数量和生命周期均不确定,可能方生方死,也可能常驻内存,如何在满足其要求的同时,尽可能降低系统负载?
一个基本事实是,线程的创建和销毁都是需要额外的系统资源的,如果线程的生命周期很短,那么相对于实际干活的时间,来回重复创建和销毁就显得很不划算,但也不能让线程执行完任务之后耗着不走,因此就需要一个比较科学合理的布局,来管控线程,一个比较成熟的方案是:在上述情况下,将线程放入一个类似缓冲区的池子中,对于生命周期很短的任务,那么什么时候需要线程就从池子中捞出来干活,干完活就放回池子且让线程保持整装待命,并通过精巧的设计使得池子中的线程数量可以动态地发生变化,让线程既可以应对并发性需求,又不会浪费系统资源,这种设计思路就是线程池。
2. 逻辑框架线程池的基本想法,是将许多线程,放置一个池子中(实际就一个结构体),只要有任务,就将任务投入池中,这些线程们通过某些机制,及时处理这些任务。为了便于管理,线程池还应当提供诸如初始化线程池、增删线程数量、检测未完成任务的数量、检测正在执行任务的线程的数量、销毁线程池等等基本操作。
要让线程池好用,主要是解决如下两个问题:
如何组织线程? 如何组织任务?3. 线程组织
从上图可以看到,线程被创建出来之后,都处于睡眠态,它们实际上是进入了条件量的等待队列中。而任务都被放入一个链表,被互斥锁保护起来。
下面是线程池里面线程们的一生:
`【1】被创建 【2】写遗书(准备好退出处理函数,防止在持有一把锁的状态中死去) 【3】试图持有互斥锁(等待任务) 【4】判断是否有任务,若无则进入条件量等待队列睡眠,若有则进入第5步 【5】从任务链表中取得一个任务 【6】释放互斥锁 【7】销毁遗书(将备用的退出处理函数弹出,避免占用内存) 【8】执行任务,完毕之后重回第2步`
线程池中的线程示例:
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;
pool->waiting_tasks--;
// 释放互斥锁
pthread_mutex_unlock(&pool->lock);
// 销毁遗书(将备用的退出处理函数弹出,避免占用内存)
pthread_cleanup_pop(0);
// 为避免在执行任务期间被强制终止,可先屏蔽取消指令
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
(p->do_task)(p->arg); // 执行任务
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
// 释放任务节点
free(p);
}
4. 任务组织
任务实质上是用户需要交给线程池执行的函数,为了方便线程们执行,一般做法是将函数(即函数指针)及其参数存入一个任务节点,并将节点链成一个链表。
对于任务链表,主要操作无非是:
- 设计任务节点
- 构造任务节点
- 在任务链表中增删任务节点
- 执行任务
设计任务节点:
struct node
{
void *(*task)(void *);
void *arg;
struct node *next;
};
- 构造任务节点:
void *f(void *arg)
{
// some code
}
struct node *p = malloc(sizeof(struct node));
p->task = f;
p->arg = NULL;
执行任务:
(p->task)(p->arg);5. 示例代码 main.c
#include "thread_pool.h"
void *mytask(void *arg)
{
int n = (int)arg;
printf("[%u][%s] ==> job will be done in %d sec...n",
(unsigned)pthread_self(), __FUNCTION__, n);
sleep(n);
printf("[%u][%s] ==> job done!n",
(unsigned)pthread_self(), __FUNCTION__);
return NULL;
}
void *count_time(void *arg)
{
int i = 0;
while(1)
{
sleep(1);
printf("sec: %dn", ++i);
}
}
int main(void)
{
pthread_t a;
pthread_create(&a, NULL, count_time, NULL);
// 1, initialize the pool
thread_pool *pool = malloc(sizeof(thread_pool));
init_pool(pool, 2);
// 2, throw tasks
printf("throwing 3 tasks...n");
add_task(pool, mytask, (void *)(rand()%10));
add_task(pool, mytask, (void *)(rand()%10));
add_task(pool, mytask, (void *)(rand()%10));
// 3, check active threads number
printf("current thread number: %dn",
remove_thread(pool, 0));
sleep(9);
// 4, throw tasks
printf("throwing another 2 tasks...n");
add_task(pool, mytask, (void *)(rand()%10));
add_task(pool, mytask, (void *)(rand()%10));
// 5, add threads
add_thread(pool, 2);
sleep(5);
// 6, remove threads
printf("remove 3 threads from the pool, "
"current thread number: %dn",
remove_thread(pool, 3));
// 7, destroy the pool
destroy_pool(pool);
return 0;
}
pthread_cleanup.c
#includethread_pool.h#include #include #include #include #include #include #include #include pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER; void *count(void *arg) { int i=1; while(1) { sleep(1); printf("sec: %dn", i++); } } void handler(void *arg) { printf("[%u] is cancelled.n", (unsigned)pthread_self()); pthread_mutex_t *pm = (pthread_mutex_t *)arg; pthread_mutex_unlock(pm); } void *routine(void *arg) { #ifdef CLEANUP pthread_cleanup_push(handler, (void *)&m); #endif pthread_mutex_lock(&m); printf("[%u] lock the mutex!n", (unsigned)pthread_self()); sleep(2); printf("[%u]: job finished!n", (unsigned)pthread_self()); pthread_mutex_unlock(&m); printf("[%u] unlock the mutex!n", (unsigned)pthread_self()); #ifdef CLEANUP pthread_cleanup_pop(0); #endif pthread_exit(NULL); } int main(int argc, char **argv) { pthread_t t, t1, t2; pthread_create(&t, NULL, count, NULL); pthread_create(&t1, NULL, routine, NULL); pthread_create(&t2, NULL, routine, NULL); printf("[%u] ==> t1n", (unsigned)t1); printf("[%u] ==> t2n", (unsigned)t2); printf("[%u] ==> mainn", (unsigned)pthread_self()); sleep(1); pthread_cancel(t1); pthread_cancel(t2); sleep(2); pthread_mutex_lock(&m); printf("[%u] locked the mutex!n", (unsigned)pthread_self()); pthread_mutex_unlock(&m); exit(0); }
#ifndef _THREAD_POOL_H_ #define _THREAD_POOL_H_ #includethread_pool.c#include #include #include #include #include #include #include #define MAX_WAITING_TASKS 1000 #define MAX_ACTIVE_THREADS 20 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; 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());
pthread_mutex_unlock((pthread_mutex_t *)arg);
}
void *routine(void *arg)
{
#ifdef DEBUG
printf("[%u] is started.n",
(unsigned)pthread_self());
#endif
thread_pool *pool = (thread_pool *)arg;
struct task *p;
while(1)
{
//================================================//
pthread_cleanup_push(handler, (void *)&pool->lock);
pthread_mutex_lock(&pool->lock);
//================================================//
// 1, no task, and is NOT shutting down, then wait
while(pool->waiting_tasks == 0 && !pool->shutdown)
{
pthread_cond_wait(&pool->cond, &pool->lock);
}
// 2, no task, and is shutting down, then exit
if(pool->waiting_tasks == 0 && pool->shutdown == true)
{
pthread_mutex_unlock(&pool->lock);
pthread_exit(NULL); // CANNOT use 'break';
}
// 3, have some task, then consume it
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);
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);
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("allocate memory error");
return false;
}
pool->task_list->next = NULL;
pool->max_waiting_tasks = MAX_WAITING_TASKS;
pool->waiting_tasks = 0;
pool->active_threads = threads_number;
int i;
for(i=0; iactive_threads; i++)
{
if(pthread_create(&((pool->tids)[i]), NULL,
routine, (void *)pool) != 0)
{
perror("create threads error");
return false;
}
#ifdef DEBUG
printf("[%u]:[%s] ==> tids[%d]: [%u] is created.n",
(unsigned)pthread_self(), __FUNCTION__,
i, (unsigned)pool->tids[i]);
#endif
}
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("allocate memory error");
return false;
}
new_task->do_task = do_task;
new_task->arg = arg;
new_task->next = NULL;
//============ LOCK =============//
pthread_mutex_lock(&pool->lock);
//===============================//
if(pool->waiting_tasks >= MAX_WAITING_TASKS)
{
pthread_mutex_unlock(&pool->lock);
fprintf(stderr, "too many tasks.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++;
//=========== UNLOCK ============//
pthread_mutex_unlock(&pool->lock);
//===============================//
#ifdef DEBUG
printf("[%u][%s] ==> a new task has been added.n",
(unsigned)pthread_self(), __FUNCTION__);
#endif
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++;
#ifdef DEBUG
printf("[%u]:[%s] ==> tids[%d]: [%u] is created.n",
(unsigned)pthread_self(), __FUNCTION__,
i, (unsigned)pool->tids[i]);
#endif
}
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;
#ifdef DEBUG
printf("[%u]:[%s] ==> cancelling tids[%d]: [%u]...n",
(unsigned)pthread_self(), __FUNCTION__,
i, (unsigned)pool->tids[i]);
#endif
}
if(i == pool->active_threads-1)
return -1;
else
{
pool->active_threads = i+1;
return i+1;
}
}
bool destroy_pool(thread_pool *pool)
{
// 1, activate all threads
pool->shutdown = true;
pthread_cond_broadcast(&pool->cond);
// 2, wait for their exiting
int i;
for(i=0; iactive_threads; i++)
{
errno = pthread_join(pool->tids[i], NULL);
if(errno != 0)
{
printf("join tids[%d] error: %sn",
i, strerror(errno));
}
else
printf("[%u] is joinedn", (unsigned)pool->tids[i]);
}
// 3, free memories
free(pool->task_list);
free(pool->tids);
free(pool);
return true;
}
Makefile
CC = gcc CFLAGS = -O0 -Wall -g -lpthread test:main.c thread_pool.c $(CC) $^ -o $@ $(CFLAGS) debug:main.c thread_pool.c $(CC) $^ -o $@ $(CFLAGS) -DDEBUG clean: $(RM) .*.sw? test debug *.o .PHONY:all clean
6.线程池接口文档
10.面试题
编写一个程序,用线程池实现并行文件或目录的拷贝。
解析
本题主要考察对线程池的实际应用,对目录进行拷贝时,可将文件复制封装为线程池任务,主线程负责递归地将目录下的所有文件打开并投入线程池,直到将所有文件拷贝结束为止。
threadpool.h
#ifndef _THREAD_POOL_H_ #define _THREAD_POOL_H_ #include#include #include #include #include #include #include #include #define MAX_WAITING_TASKS 1000 #define MAX_ACTIVE_THREADS 20 #define BUFSIZE 100 #define PATHSIZE 100 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; 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
threadpool.c
#include "threadpool.h"
void handler(void *arg)
{
pthread_mutex_unlock((pthread_mutex_t *)arg);
}
void *routine(void *arg)
{
#ifdef DEBUG
printf("[%u] is started.n",
(unsigned)pthread_self());
#endif
thread_pool *pool = (thread_pool *)arg;
struct task *p;
while(1)
{
//================================================//
pthread_cleanup_push(handler, (void *)&pool->lock);
pthread_mutex_lock(&pool->lock);
//================================================//
// 1, no task, and is NOT shutting down, then wait
while(pool->waiting_tasks == 0 && !pool->shutdown)
{
pthread_cond_wait(&pool->cond, &pool->lock);
}
// 2, no task, and is shutting down, then exit
if(pool->waiting_tasks == 0 && pool->shutdown == true)
{
pthread_mutex_unlock(&pool->lock);
pthread_exit(NULL); // CANNOT use 'break';
}
// 3, have some task, then consume it
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);
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);
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("allocate memory error");
return false;
}
pool->task_list->next = NULL;
pool->max_waiting_tasks = MAX_WAITING_TASKS;
pool->waiting_tasks = 0;
pool->active_threads = threads_number;
int i;
for(i=0; iactive_threads; i++)
{
if(pthread_create(&((pool->tids)[i]), NULL,
routine, (void *)pool) != 0)
{
perror("create threads error");
return false;
}
#ifdef DEBUG
printf("[%u]:[%s] ==> tids[%d]: [%u] is created.n",
(unsigned)pthread_self(), __FUNCTION__,
i, (unsigned)pool->tids[i]);
#endif
}
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("allocate memory error");
return false;
}
new_task->do_task = do_task;
new_task->arg = arg;
new_task->next = NULL;
//============ LOCK =============//
pthread_mutex_lock(&pool->lock);
//===============================//
if(pool->waiting_tasks >= MAX_WAITING_TASKS)
{
pthread_mutex_unlock(&pool->lock);
fprintf(stderr, "too many tasks.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++;
//=========== UNLOCK ============//
pthread_mutex_unlock(&pool->lock);
//===============================//
#ifdef DEBUG
printf("[%u][%s] ==> a new task has been added.n",
(unsigned)pthread_self(), __FUNCTION__);
#endif
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++;
#ifdef DEBUG
printf("[%u]:[%s] ==> tids[%d]: [%u] is created.n",
(unsigned)pthread_self(), __FUNCTION__,
i, (unsigned)pool->tids[i]);
#endif
}
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;
#ifdef DEBUG
printf("[%u]:[%s] ==> cancelling tids[%d]: [%u]...n",
(unsigned)pthread_self(), __FUNCTION__,
i, (unsigned)pool->tids[i]);
#endif
}
if(i == pool->active_threads-1)
return -1;
else
{
pool->active_threads = i+1;
return i+1;
}
}
bool destroy_pool(thread_pool *pool)
{
// 1, activate all threads
pool->shutdown = true;
pthread_cond_broadcast(&pool->cond);
// 2, wait for their exiting
int i;
for(i=0; iactive_threads; i++)
{
errno = pthread_join(pool->tids[i], NULL);
if(errno != 0)
{
printf("join tids[%d] error: %sn",
i, strerror(errno));
}
}
// 3, free memories
free(pool->task_list);
free(pool->tids);
free(pool);
return true;
}
copy.c
#includemain.c#include #include #include #include "thread_pool.h" int copyfile(int fd_src, int fd_dst) { char buf[BUFSIZE]; int nread, nwrite, ntotal=0; while(1) { bzero(buf, BUFSIZE); nread = read(fd_src, buf, BUFSIZE); if(nread == 0) break; else if(nread == -1) { perror("read error"); return -1; } char *p = buf; while(nread > 0) { nwrite = write(fd_dst, p, nread); nread -= nwrite; p += nwrite; ntotal += nwrite; } } return ntotal; } void *mytask(void *arg) { int fd[2]; fd[0] = ((int *)arg)[0]; fd[1] = ((int *)arg)[1]; copyfile(fd[0], fd[1]); return NULL; } void copydir(thread_pool *pool, const char *dir_src, const char *dir_dst) { char abs_ori[PATHSIZE] = {0}; char abs_src[PATHSIZE] = {0}; char abs_dst[PATHSIZE] = {0}; getcwd(abs_ori, PATHSIZE); chdir(dir_src); getcwd(abs_src, PATHSIZE); chdir(abs_ori); mkdir(dir_dst, 0777); chdir(dir_dst); getcwd(abs_dst, PATHSIZE); DIR *dp_src; dp_src = opendir(abs_src); int fd[2]; struct dirent *ep; struct stat *file_info; while(1) { chdir(abs_src); ep = readdir(dp_src); if(ep == NULL) break; else if(!strcmp(ep->d_name, ".") || !strcmp(ep->d_name, "..")) continue; file_info = calloc(1, sizeof(struct stat)); stat(ep->d_name, file_info); if(S_ISDIR(file_info->st_mode)) { chdir(abs_dst); mkdir(ep->d_name, 0777); chdir(ep->d_name); char path[PATHSIZE] = {0}; getcwd(path, PATHSIZE); chdir(abs_src); copydir(pool, ep->d_name, path); } else if(S_ISREG(file_info->st_mode)) { fd[0] = open(ep->d_name, O_RDONLY); chdir(abs_dst); fd[1] = open(ep->d_name, O_WRONLY|O_CREAT|O_TRUNC, 0644); add_task(pool, mytask, (void *)fd); } } } int main(int argc, char **argv) { if(argc != 3) exit(0); // 1, initialize the pool thread_pool *pool = malloc(sizeof(thread_pool)); init_pool(pool, 3); struct stat *file_info = calloc(1, sizeof(struct stat)); stat(argv[1], file_info); // 2, throw tasks if(S_ISREG(file_info->st_mode)) { int fd[2]; fd[0] = open(argv[1], O_RDONLY); fd[1] = open(argv[2], O_CREAT|O_WRONLY|O_TRUNC, 0644); add_task(pool, mytask, (void *)fd); } else if(S_ISDIR(file_info->st_mode)) { copydir(pool, argv[1], argv[2]); } else printf("file format is NOT supported.n"); // 3, destroy the pool destroy_pool(pool); return 0; }
#includeMakefile#include #include #include #include "threadpool.h" int copyfile(int fd_src, int fd_dst) { char buf[BUFSIZE]; int nread, nwrite, ntotal=0; while(1) { bzero(buf, BUFSIZE); nread = read(fd_src, buf, BUFSIZE); if(nread == 0) break; else if(nread == -1) { perror("read error"); return -1; } char *p = buf; while(nread > 0) { nwrite = write(fd_dst, p, nread); nread -= nwrite; p += nwrite; ntotal += nwrite; } } return ntotal; } void *mytask(void *arg) { int fd[2]; fd[0] = ((int *)arg)[0]; fd[1] = ((int *)arg)[1]; copyfile(fd[0], fd[1]); return NULL; } void copydir(thread_pool *pool, const char *dir_src, const char *dir_dst) { char abs_ori[PATHSIZE] = {0}; char abs_src[PATHSIZE] = {0}; char abs_dst[PATHSIZE] = {0}; getcwd(abs_ori, PATHSIZE); chdir(dir_src); getcwd(abs_src, PATHSIZE); chdir(abs_ori); mkdir(dir_dst, 0777); chdir(dir_dst); getcwd(abs_dst, PATHSIZE); DIR *dp_src; dp_src = opendir(abs_src); int fd[2]; struct dirent *ep; struct stat *file_info; while(1) { chdir(abs_src); ep = readdir(dp_src); if(ep == NULL) break; else if(!strcmp(ep->d_name, ".") || !strcmp(ep->d_name, "..")) continue; file_info = calloc(1, sizeof(struct stat)); stat(ep->d_name, file_info); if(S_ISDIR(file_info->st_mode)) { chdir(abs_dst); mkdir(ep->d_name, 0777); chdir(ep->d_name); char path[PATHSIZE] = {0}; getcwd(path, PATHSIZE); chdir(abs_src); copydir(pool, ep->d_name, path); } else if(S_ISREG(file_info->st_mode)) { fd[0] = open(ep->d_name, O_RDONLY); chdir(abs_dst); fd[1] = open(ep->d_name, O_WRONLY|O_CREAT|O_TRUNC, 0644); add_task(pool, mytask, (void *)fd); } } } int main(int argc, char **argv) { if(argc != 3) exit(0); // 1, initialize the pool thread_pool *pool = malloc(sizeof(thread_pool)); init_pool(pool, 3); struct stat *file_info = calloc(1, sizeof(struct stat)); stat(argv[1], file_info); // 2, throw tasks if(S_ISREG(file_info->st_mode)) { int fd[2]; fd[0] = open(argv[1], O_RDONLY); fd[1] = open(argv[2], O_CREAT|O_WRONLY|O_TRUNC, 0644); add_task(pool, mytask, (void *)fd); } else if(S_ISDIR(file_info->st_mode)) { copydir(pool, argv[1], argv[2]); } else printf("file format is NOT supported.n"); // 3, destroy the pool destroy_pool(pool); return 0; }
CC = gcc CFLAGS = -O0 -Wall -g -lpthread copy:copy.c thread_pool.c $(CC) $^ -o $@ $(CFLAGS) debug:copy.c thread_pool.c $(CC) $^ -o $@ $(CFLAGS) -DDEBUG clean: $(RM) .*.sw? copy debug *.o .PHONY:all clean结束篇总结
整套课程,都是博主用心良苦整理,是以前企业教育培训的课程,价值连城,排版、细节、内容等,都要追求精益求精,好好学习吧少年!
源码获取
活动地址:毕业季·进击的技术er



