概述:之前总是听别人说线程池,一直没接触过,借业余时间学习了一下,现在自己简单的封装了一下,也只是在学习的层面,用到实际操作可能还需很多优化修改。
1,先看封装的结构体吧,sky_pool.h文件内容,主要就是定义封装了一下线程池所需用到的参数等。
#ifndef _SKY_POOL_H_
#define _SKY_POOL_H_
#include <stdint.h>
#include <pthread.h>
typedef struct worker worker_t;
typedef struct thread_pool thread_pool_t;
typedef struct tpool_ctl tpool_ctl_t;
typedef void (*thread_cb_t)(void *arg);
struct worker {
thread_cb_t cb; /*任务回调函数*/
void *arg; /*回调函数参数*/
worker_t *next;
};
struct thread_pool {
pthread_mutex_t work_lock;
pthread_cond_t work_cond;
pthread_t *thread_id;
uint8_t pool_destory; /*线程池销毁标志*/
uint32_t thread_num; /*初始创建线程数目*/
uint32_t worklist_size; /*当前任务数目*/
worker_t *worklist; /*具体需要执行的任务链表*/
};
typedef void (*tpool_addwork_t)(tpool_ctl_t *, thread_cb_t , void *);
typedef void (*tpool_destory_t)(tpool_ctl_t *);
struct tpool_ctl {
struct thread_pool tp; /*线程池结构*/
tpool_addwork_t add;
tpool_destory_t del;
};
tpool_ctl_t *tpctl_create(uint32_t thread_num);
#endif
2,接下来就是一个sky_pool.c文件,主要是实现线程池的创建,初始化,任务添加等。
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <sys/types.h>
#include <pthread.h>
#include <assert.h>
#include "sky_pool.h"
/*互斥锁加锁解锁封装*/
static void tpctl_lock(tpool_ctl_t *tpctl)
{
pthread_mutex_lock(&(tpctl->tp.work_lock));
}
static void tpctl_unlock(tpool_ctl_t *tpctl)
{
pthread_mutex_unlock(&(tpctl->tp.work_lock));
}
/*线程入口函数*/
static void *thread_runing(void *arg)
{
tpool_ctl_t *tpctl = arg;
printf ("starting thread %08x\n", pthread_self ());
while (1) {
tpctl_lock(tpctl);
while (!tpctl->tp.pool_destory && 0 == tpctl->tp.worklist_size) {
/*无任务且不执行线程池销毁操作,线程阻塞等待*/
printf("thread %08x waiting...\n",pthread_self ());
pthread_cond_wait(&(tpctl->tp.work_cond), &(tpctl->tp.work_lock));
}
/*判断是否销毁线程*/
if (tpctl->tp.pool_destory) {
tpctl_unlock(tpctl);
printf("thread %08x exit...\n",pthread_self ());
pthread_exit(NULL);
}
assert(tpctl->tp.worklist != NULL);
assert(tpctl->tp.worklist_size != 0);
if (NULL != tpctl->tp.worklist && tpctl->tp.worklist_size > 0) {
/*取出任务*/
tpctl->tp.worklist_size --;
worker_t *current_work = tpctl->tp.worklist;
tpctl->tp.worklist = current_work->next;
tpctl_unlock(tpctl);
/*回调函数,执行任务*/
printf ("thread %08x work...\n", pthread_self ());
current_work->cb(current_work->arg);
free(current_work);
current_work = NULL;
}
}
}
/*添加任务到工作链表*/
static void tpool_addworker(tpool_ctl_t *tpctl, thread_cb_t cb, void *arg)
{
worker_t *new_work = (worker_t *)malloc(sizeof(worker_t));
new_work->cb = cb;
new_work->arg = arg;
new_work->next = NULL;
tpctl_lock(tpctl);
worker_t *worklist = tpctl->tp.worklist;
if (NULL != worklist) {
while (NULL != worklist->next) {
worklist = worklist->next;
}
worklist->next = new_work;
} else {
tpctl->tp.worklist = new_work;
}
tpctl->tp.worklist_size ++;
tpctl_unlock(tpctl);
/*发送信号,唤醒某个线程执行任务*/
pthread_cond_signal(&(tpctl->tp.work_cond));
}
/*线程池销毁*/
static void tpool_destory(tpool_ctl_t *tpctl)
{
if (tpctl->tp.pool_destory) {
return ;
}
tpctl->tp.pool_destory = 1;
pthread_cond_broadcast (&(tpctl->tp.work_cond));
/*销毁线程*/
uint32_t i;
for (i = 0 ; i < tpctl->tp.thread_num ; i ++) {
pthread_join(tpctl->tp.thread_id[i],NULL);
}
free(tpctl->tp.thread_id);
/*销毁任务链表*/
worker_t *work = NULL;
while (NULL != tpctl->tp.worklist) {
work = tpctl->tp.worklist;
tpctl->tp.worklist = tpctl->tp.worklist->next;
free(work);
}
/*互斥锁销毁*/
pthread_mutex_destroy(&(tpctl->tp.work_lock));
pthread_cond_destroy(&(tpctl->tp.work_cond));
free(tpctl);
tpctl = NULL;
}
/*线程池的初始化*/
static void tpctl_init(tpool_ctl_t *tpctl, uint32_t thread_num)
{
pthread_mutex_init(&(tpctl->tp.work_lock),NULL);
pthread_cond_init(&(tpctl->tp.work_cond),NULL);
tpctl->tp.pool_destory = 0;
tpctl->tp.thread_num = thread_num;
tpctl->tp.worklist_size = 0;
tpctl->tp.thread_id = (pthread_t *)malloc(thread_num * sizeof(pthread_t));
tpctl->tp.worklist = NULL;
uint32_t i;
/*创建设定数目的子线程*/
for (i = 0 ; i < thread_num ; i++) {
pthread_create(&(tpctl->tp.thread_id[i]), NULL, thread_runing, tpctl);
}
}
/*创建线程池并初始化*/
tpool_ctl_t *tpctl_create(uint32_t thread_num)
{
tpool_ctl_t *tpctl = (tpool_ctl_t *)malloc(sizeof(tpool_ctl_t));
if (NULL == tpctl) {
return NULL;
}
tpctl_init(tpctl,thread_num);
tpctl->add = tpool_addworker;
tpctl->del = tpool_destory;
return tpctl;
}
3,封装文件的使用。我们创建一个main.c文件,调用我们封装好的函数即可实现线程池操作了。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "sky_pool.h"
#define THREAD_NUM 3
void callback(void *arg)
{
printf("Be Yourself\n");
}
void callback1(void *arg)
{
sleep(1);
printf("Peace&Love\n");
}
void callback2(void *arg)
{
printf("Keep Real\n");
sleep(2);
}
int main()
{
/*创建线程池*/
tpool_ctl_t *tpctl = tpctl_create(THREAD_NUM);
if (NULL == tpctl) {
return 1;
}
while (1) {
sleep(2);
/*添加任务*/
tpctl->add(tpctl,callback,NULL);
tpctl->add(tpctl,callback1,NULL);
tpctl->add(tpctl,callback2,NULL);
sleep(5);
break;
}
/*线程池销毁*/
tpctl->del(tpctl);
return 0;
}
4,总结:整体来说,线程池的通用简单实现还是不难的,我这边封装也是想多练练自己函数封装的能力,尽量做到简洁有效,让人一目了然。继续学习吧,保持一个封装的好习惯。
5,参考博文
一个Linux下C线程池的实现(转)