核心 API 的实现
1. thpool_init()
该函数用于创建一个线程池,先明确线程池的定义:
-
typedef struct thpool_{
-
thread** threads; /* pointer to threads */
-
volatile int num_threads_alive; /* threads currently alive */
-
volatile int num_threads_working; /* threads currently working */
-
pthread_mutex_t thcount_lock; /* used for thread count etc */
-
pthread_cond_t threads_all_idle; /* signal to thpool_wait */
-
jobqueue jobqueue; /* job queue */
-
} thpool_;
thpool_init() 的实现思路:
-
分配 struct thpool_:
-
malloc(sizeof(struct thpool_))
-
初始化 struct thpool_;
-
-
malloc(num_threads * sizeof(struct thread *))
-
thread_init(thpool_p, &thpool_p->threads[n], n);
-
jobqueue_init(&thpool_p->jobqueue)
-
初始化 jobqueue:
-
创建用户指定数目的线程,用一个二级指针来指向这一组线程;
-
-
返回 struct thpool_ *;
-
2. thpool_add_work()
该函数用于往线程池里添加一个任务,先明确任务的定义:
-
typedef struct job{
-
struct job* prev; /* pointer to previous job */
-
void (*function)(void* arg); /* function pointer */
-
void* arg; /* function's argument */
-
} job;
程序里是用队列来管理任务的,这里的 job 首先是一个队列节点,携带的数据是 function + arg。
thpool_add_work 的实现思路:
-
分配 struct job:
-
malloc(sizeof(struct job))
-
-
初始化 struct job;
-
-
newjob->function=function_p;
-
newjob->arg=arg_p;
-
-
添加到队列中:
-
-
jobqueue_push(&thpool_p->jobqueue, newjob);
3. thpool_pause() 和 thpool_resume()
thpool_pause() 用于暂停所有的线程,通过信号机制来实现:
-
void thpool_pause(thpool_* thpool_p) {
-
int n;
-
for (n=0; n < thpool_p->num_threads_alive; n++){
-
pthread_kill(thpool_p->threads[n]->pthread, SIGUSR1);
-
}
-
}
给所有工作线程发送
SIGUSR1
,该信号的处理行为就是让线程休眠:-
static void thread_hold(int sig_id) {
-
(void)sig_id;
-
threads_on_hold = 1;
-
while (threads_on_hold){
-
sleep(1);
-
}
-
}
只需要 thpool_resume() 中,将 threads_on_hold = 0,就可以让线程返回到原来被中止时的工作状态。
4. thpool_wait()
wait 的实现比较简单,只要还有任务或者还有线程处于工作状态,就执行 pthread 的 wait 操作:
-
while (thpool_p->jobqueue.len || thpool_p->num_threads_working) {
-
pthread_cond_wait(&thpool_p->threads_all_idle, &thpool_p->thcount_lock);
-
}
到此,我感觉已经没有太多难点了,感兴趣的小伙伴们可以自行查阅源码。
四、测试用例
优秀的开源项目通常会附带丰富的测试用例,此项目也不例外:
-
memleaks.sh:测试是否发生内存泄露;
-
threadpool.sh: 测试线程池是否能正确地执行任务;
-
pause_resume.sh:测试 pause 和 resume 是否正常;
-
wait.sh:测试 wait 功能是否正常;
-
heap_stack_garbage:测试堆栈内有垃圾数据时的情况;
思考技术,也思考人生
要学习技术,更要学习如何生活。
最近在看的书:
《精要主义》
收获了什么?
身体是一种资产:
-
身体是用来达到个人贡献峰值的珍贵资产,而最常见用来破坏这种资产的方式是:缺乏睡眠。
-
有的人可以很轻易地让自己拼命工作,并且认为自己强大到可以通过减少睡眠来尽快实现自己的目标。而事实是,他们绝大多数人只是习惯了疲惫状态,以至于已经忘记充分休息后的高效学习、工作是什么感觉。
-
正确的做法是:系统地、有意识地为睡眠留下一席之地,为每天的生活保留一部分精力和创造力、解决问题的能力,以应对一些意外情况。
你和我各有一个苹果,如果我们交换苹果的话,我们还是只有一个苹果。但当你和我各有一个想法,我们交换想法的话,我们就都有两个想法了。
觉得文章对你有价值,不妨点个 在看和赞。
-
点击查看大图