Linux 线程池源码剖析

1 了解线程池

1-1线程池的概述

由一个任务队列和一组处理队列的线程组成。一旦工作进程需要处理某个可能“阻塞”的操作,不用自己操作,将其作为一个任务放到线程池的队列,接着会被某个空闲线程提取处理。

Linux 线程池源码剖析_第1张图片

1-2线程池的组件

任务 		 待处理的工作,通常由标识、上下文和处理函数组成。
任务队列 	 按顺序保存待处理的任务序列,等待线程中的线程组处理。
线程池 		 由多个已启动的一组线程组成。
条件变量 	 一种同步机制,允许线程挂起,直到共享数据上的某些条件得到满足。
互斥锁 		 保证在任一时刻,只能有一个线程访问该对象。

2 互斥锁 与 条件变量 自定义封装 声明 与 定义

thread.h

#ifndef _DEMO_THREAD_H_INCLUDED_
#define _DEMO_THREAD_H_INCLUDED_

#include 
#include 
#include 
#include 
#include 
#include 
#include 

typedef intptr_t        int_t;
typedef uintptr_t       uint_t;

#define  OK          0
#define  ERROR      -1

//---------互斥量(互斥锁)接口的封装-----------定义:thread_mutex.c
int thread_mutex_create(pthread_mutex_t *mtx);				//线程 互斥锁的 创建
int thread_mutex_destroy(pthread_mutex_t *mtx);				//线程 互斥锁的 销毁
int thread_mutex_lock(pthread_mutex_t *mtx);				//线程 互斥锁的 加锁
int thread_mutex_unlock(pthread_mutex_t *mtx);				//线程 互斥锁的 解锁



//---------条件变量接口的封装-----------------定义:thread_cond.c
int thread_cond_create(pthread_cond_t *cond);				//线程 条件变量的 创建
int thread_cond_destroy(pthread_cond_t *cond);				//线程 条件变量的 销毁
int thread_cond_signal(pthread_cond_t *cond);				//线程 条件变量的 信号发送
int thread_cond_wait(pthread_cond_t *cond,					//线程 条件变量的 信号接受
					 pthread_mutex_t *mtx);	

#endif /* _DEMO_THREAD_H_INCLUDED_ */

thread_mutex.c

#include "thread.h"

//互斥锁的创建
int thread_mutex_create(pthread_mutex_t *mtx)
{
    int                   err;
    pthread_mutexattr_t  attr; 					 //互斥锁属性变量
   //1对互斥变量属性 pthread_mutexattr_t 初始化
    err = pthread_mutexattr_init(&attr);
    if (err != 0) {
        fprintf(stderr, "pthread_mutexattr_init() failed, reason: %s\n",strerror(errno));
        return ERROR;
    }

   //2设置互斥变量防 死锁检测 PTHREAD_MUTEX_ERRORCHECK 不允许同一个线程多次获取同一个锁导致的死锁
    err = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);
    if (err != 0) {
	fprintf(stderr, "pthread_mutexattr_settype(PTHREAD_MUTEX_ERRORCHECK) failed, reason: %s\n",strerror(errno));
        return ERROR;
    }

    //3对创建的互斥锁 mtx 设置 attr 属性
    err = pthread_mutex_init(mtx, &attr);
    if (err != 0) {
        fprintf(stderr,"pthread_mutex_init() failed, reason: %s\n",strerror(errno));
        return ERROR;
    }
    //3销毁互斥锁属性变量
    err = pthread_mutexattr_destroy(&attr);
    if (err != 0) {
	fprintf(stderr,"pthread_mutexattr_destroy() failed, reason: %s\n",strerror(errno));
    }

    return OK;
}

//互斥锁的销毁
int thread_mutex_destroy(pthread_mutex_t *mtx)
{
    int  err;

    err = pthread_mutex_destroy(mtx);
    if (err != 0) {
        fprintf(stderr,"pthread_mutex_destroy() failed, reason: %s\n",strerror(errno));
        return ERROR;
    }
    return OK;
}


//互斥锁上锁
int thread_mutex_lock(pthread_mutex_t *mtx)
{
    int  err;

    err = pthread_mutex_lock(mtx);
    if (err == 0) {
        return OK;
    }
	fprintf(stderr,"pthread_mutex_lock() failed, reason: %s\n",strerror(errno));

    return ERROR;
}

//互斥锁解锁
int thread_mutex_unlock(pthread_mutex_t *mtx)
{
    int  err;

    err = pthread_mutex_unlock(mtx);

#if 0
    ngx_time_update();
#endif

    if (err == 0) {
        return OK;
    }
	
	fprintf(stderr,"pthread_mutex_unlock() failed, reason: %s\n",strerror(errno));
    return ERROR;
}

thread_cond.c

#include "thread.h"

int thread_cond_create(pthread_cond_t *cond)
{
    int  err;
    err = pthread_cond_init(cond, NULL);
    if (err == 0) {
        return OK;
    }
    fprintf(stderr, "pthread_cond_init() failed, reason: %s\n",strerror(errno));
    return ERROR;
}

int thread_cond_destroy(pthread_cond_t *cond)
{
    int  err;
    err = pthread_cond_destroy(cond);
    if (err == 0) {
        return OK;
    }

	fprintf(stderr, "pthread_cond_destroy() failed, reason: %s\n",strerror(errno));
    return ERROR;
}

int thread_cond_signal(pthread_cond_t *cond)
{
    int  err;
    err = pthread_cond_signal(cond);
    if (err == 0) {
        return OK;
    }
	fprintf(stderr, "pthread_cond_signal() failed, reason: %s\n",strerror(errno));
   return ERROR;
}

int thread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mtx)
{
    int  err;
    err = pthread_cond_wait(cond, mtx);
    if (err == 0) {
        return OK;
    }
 	fprintf(stderr, "pthread_cond_wait() failed, reason: %s\n",strerror(errno));
   return ERROR;
}

3 线程池的 声明 与 定义

thread_pool.h

#ifndef _THREAD_POOL_H_INCLUDED_
#define _THREAD_POOL_H_INCLUDED_


#include "thread.h"

#define DEFAULT_THREADS_NUM 4						//默认线程池线程数量
#define DEFAULT_QUEUE_NUM  65535					//任务队列最大的数量


typedef unsigned long         atomic_uint_t;		//无符号整形
typedef struct thread_task_s  thread_task_t;		//任务
typedef struct thread_pool_s  thread_pool_t;		//线程池


//任务
struct thread_task_s {
    thread_task_t       *next;						//下一个任务
    uint_t               id;						//任务号
    void                *ctx;						//上下文(任务函数的:参数)
    void               (*handler)(void *data);		//任务函数
};

//控制 任务队列 
typedef struct {
    thread_task_t        *first;
    thread_task_t        **last;
} thread_pool_queue_t;

//任务队列初始化宏替换
#define thread_pool_queue_init(q)      \
    (q)->first = NULL;                 \
    (q)->last = &(q)->first

//线程池
struct thread_pool_s {
    pthread_mutex_t       mtx;						//线程池的--互斥锁
    thread_pool_queue_t   queue;					//线程池的--任务队列的控制
    int_t                 waiting;					//线程池的--任务队列的任务数
    pthread_cond_t        cond;          			//线程池的--条件变量

    char                  *name;					//线程池的名字
    uint_t                threads;					//线程池的线程数量
    int_t                 max_queue;				//线程池任务队列最大长度
};

thread_task_t *thread_task_alloc(size_t size);
int_t thread_task_post(thread_pool_t *tp, thread_task_t *task);
thread_pool_t* thread_pool_init();
void thread_pool_destroy(thread_pool_t *tp);

#endif /* _THREAD_POOL_H_INCLUDED_ */

thread_pool.c

#include "thread_pool.h"

static void thread_pool_exit_handler(void *data);
//线程处理的函数
static void *thread_pool_cycle(void *data);
static int_t thread_pool_init_default(thread_pool_t *tpp, char *name);

static uint_t       thread_pool_task_id;					//任务队列的任务id

static int debug = 0;

thread_pool_t* thread_pool_init()
{
    int             err;
    pthread_t       tid;									//线程的表示符
    uint_t          n;
    pthread_attr_t  attr; 									//线程的属性变量
    //1创建线程池并分配内存
    thread_pool_t   *tp=NULL;  
    tp = calloc(1,sizeof(thread_pool_t));

    if(tp == NULL){
		fprintf(stderr, "thread_pool_init: calloc failed!\n");
    	return NULL;	
    }
    //1线程池默认初始化
    thread_pool_init_default(tp, NULL);
  
    //2初始线程池的任务队列(宏函数替换):任务队列控制指针的初始化
    thread_pool_queue_init(&tp->queue);

    //3创建互斥锁
    if (thread_mutex_create(&tp->mtx) != OK) {
	free(tp);
        return NULL;
    }

    //4创建条件变量
    if (thread_cond_create(&tp->cond) != OK) {
        (void) thread_mutex_destroy(&tp->mtx);
		free(tp);
        return NULL;
    }
    //5初始化线程的属性变量
    err = pthread_attr_init(&attr);
    if (err) {
        fprintf(stderr, "pthread_attr_init() failed, reason: %s\n",strerror(errno));
		free(tp);
        return NULL;
    }
    //6设置线程池的线程的属性
    //PTHREAD_CREATE_DETACHED创建时线程为分离状态(detached)
    //主线程使用pthread_join无法等待结束的子线程
    err = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
    if (err) {
        fprintf(stderr, "pthread_attr_setdetachstate() failed, reason: %s\n",strerror(errno));
		free(tp);
        return NULL;
    }
    //7创建线程池里的处理线程
    for (n = 0; n < tp->threads; n++) {
        err = pthread_create(&tid, &attr, thread_pool_cycle, tp);	//创建线程
        if (err) {
            fprintf(stderr, "pthread_create() failed, reason: %s\n",strerror(errno));
			free(tp);
            return NULL;
        }
    }
    //8销毁线程属性变量
    (void) pthread_attr_destroy(&attr);

    return tp;
}


void thread_pool_destroy(thread_pool_t *tp)
{
    uint_t           n;
    thread_task_t    task;
    volatile uint_t  lock;

    memset(&task,'\0', sizeof(thread_task_t));
    //创建一个自杀线程任务
    task.handler = thread_pool_exit_handler;			//自杀任务的处理函数
    task.ctx = (void *) &lock;							//自杀任务的函数参数

    //将自杀任务分配给每一个处理线程
    for (n = 0; n < tp->threads; n++) {
        lock = 1;										//自杀函数的参数设置为1

        if (thread_task_post(tp, &task) != OK) {
            return;
        }
	
		//注意:如果该终止线程过程高消耗CPU,则把处理该过程的CPU让出,提高CPU利用率
        while (lock) {
            sched_yield();								//线程让出CPU使用权
        }

        //task.event.active = 0;
    }

    (void) thread_cond_destroy(&tp->cond);				//销毁线程池里的 条件变量
    (void) thread_mutex_destroy(&tp->mtx);				//销毁线程池里的 互斥锁
    free(tp);											//销毁线程池
}

//终止该函数所在的线程
static void thread_pool_exit_handler(void *data)
{
    uint_t *lock = data;

    *lock = 0;
    //销毁该线程
    pthread_exit(0);
}


thread_task_t * thread_task_alloc(size_t size)
{
    thread_task_t  *task;
    //分配1块thread_task_t+参数 的大小的内存
    task = calloc(1,sizeof(thread_task_t) + size);
    if (task == NULL) {
        return NULL;
    }

    task->ctx = task + 1;									//初始化任务的上下文(参数)

    return task;
}

//将任务投递到线程池里
int_t thread_task_post(thread_pool_t *tp, thread_task_t *task)
{
    if (thread_mutex_lock(&tp->mtx) != OK) {   				//线程池加锁
        return ERROR;
    }	
    //如果线程池等待的任务队列长度是否大于线程池任务队列最大长度
    if (tp->waiting >= tp->max_queue) {
        (void) thread_mutex_unlock(&tp->mtx);				//线程池解锁

        fprintf(stderr,"thread pool \"%s\" queue overflow: %ld tasks waiting\n",
                      tp->name, tp->waiting);
        return ERROR;
    }

    //task->event.active = 1;
   
    //初始化人物的id号 和 下一个任务的指针
    task->id = thread_pool_task_id++;
    task->next = NULL;


    //给处理的线程发送条件变量
    if (thread_cond_signal(&tp->cond) != OK) {
        (void) thread_mutex_unlock(&tp->mtx);
        return ERROR;
    }
    
    //任务队列控制指针last初始加入的任务
    *tp->queue.last = task;									//相当于 tp->queue.first=tast; 
															//初始化空的任务队列时last指针是指向first的
    tp->queue.last = &task->next;							//last指针指向task的下一个指针

    tp->waiting++;

    (void) thread_mutex_unlock(&tp->mtx);

    if(debug)fprintf(stderr,"task #%lu added to thread pool \"%s\"\n",
                   task->id, tp->name);

    return OK;
}


static void *thread_pool_cycle(void *data)
{
    thread_pool_t *tp = data;

    int                 err;
    thread_task_t       *task;								//线程处理的任务
    
    if(debug)fprintf(stderr,"thread in pool \"%s\" started\n", tp->name);
    
    for ( ;; ) {
	//-----------------线程池上锁							//上锁保护临界资源(任务队列)
        if (thread_mutex_lock(&tp->mtx) != OK) {
            return NULL;
        }

        tp->waiting--;										//拿走任务队列1个任务,任务队列数量减1

        while (tp->queue.first == NULL) {					//如果线程池的任务队列为空

       	    //******收到任务加入任务队列的条件变量*******	
			//!!!注意:只有当线程池解锁后&tp->mtx获取到锁后
			// 		  才能执行线程任务
	    if (thread_cond_wait(&tp->cond, &tp->mtx)!= OK)
            //*******************************************
            {
	        //-------------------线程池解锁
                (void) thread_mutex_unlock(&tp->mtx);
                return NULL;
            }
        }
        task = tp->queue.first;								//取任务队列第一个任务
        tp->queue.first = task->next;						//把任务队列队头指针指向下一个任务

        if (tp->queue.first == NULL) {
            tp->queue.last = &tp->queue.first;
        }
		
	 //-------------------线程池解锁
        if (thread_mutex_unlock(&tp->mtx) != OK) {
            return NULL;
        }
        if(debug) fprintf(stderr,"run task #%lu in thread pool \"%s\"\n",
                       task->id, tp->name);
		//调用任务的处理函数
        task->handler(task->ctx);

        if(debug) fprintf(stderr,"complete task #%lu in thread pool \"%s\"\n",task->id, tp->name);
        //任务的下个任务指针为NULL
        task->next = NULL;
        //处理完的任务释放资源 task里的void* ctx(参数)全部释放内存
        free(task);
       
    }
}

//线程池默认处理
static int_t thread_pool_init_default(thread_pool_t *tpp, char *name)
{
    if(tpp)
    {
        tpp->threads = DEFAULT_THREADS_NUM; 			//设置线程池线程数量
        tpp->max_queue = DEFAULT_QUEUE_NUM;				//设置线程池任务队列最大长度
	tpp->name = strdup(name?name:"default");			//设置线程池的名字
       
	if(debug)fprintf(stderr,
           "thread_pool_init, name: %s ,threads: %lu max_queue: %ld\n",
            tpp->name, tpp->threads, tpp->max_queue);

        return OK;
    }

    return ERROR;
}

任务队列插入任务控制指针变化
Linux 线程池源码剖析_第2张图片获取任务task时指针任务队列的变化
Linux 线程池源码剖析_第3张图片


4主函数内容

main.c

#include "thread_pool.h"

//作为处理函数的参数 自定义结构体
struct test{
	 int arg1;
	 int arg2;
};

//处理函数1
void task_handler1(void* data){
   static int index = 0;
   printf("Hello, this is 1th test.index=%d\r\n", index++);

}

//处理函数2
void task_handler2(void* data){
   static int index = 0;
   printf("Hello, this is 2th test.index=%d\r\n", index++);

}

//处理函数3
void task_handler3(void* data){
   static int index = 0;
   struct test *t = (struct test *) data;
   
   printf("Hello, this is 3th test.index=%d\r\n", index++);
   printf("arg1: %d, arg2: %d\n", t->arg1, t->arg2);

}

int main(int argc, char **argv)
{
   thread_pool_t* tp = NULL;										//线程池
   int i = 0;
   //1初始化线程池
   tp = thread_pool_init(); 
   sleep(1);
   
   //2创建任务
   thread_task_t * test1 = thread_task_alloc(0);					//参数0表示任务的处理函数参数大小为0
   thread_task_t * test2 = thread_task_alloc(0);					//参数0表示任务的处理函数参数大小为0
   thread_task_t * test3 = thread_task_alloc(sizeof(struct test));	//参数表示任务的处理函数参数大小为sizeof(struct test)
   //3设置任务的处理函数 和 处理函数所带的上下文(参数)
   test1->handler = task_handler1;
   test2->handler = task_handler2;
   test3->handler = task_handler3;
   ((struct test*)test3->ctx)->arg1 = 555;
   ((struct test*)test3->ctx)->arg2 = 666;

   //4将任务投递到线程池(线程池投递30个任务) 
   for(i=0;i<10;i++){
	thread_task_post(tp, test1);
 	thread_task_post(tp, test2);
   	thread_task_post(tp, test3);
   }
   sleep(15);														//等待线程处理任务

   //5销毁线程池
   // 线程里的线程会调用一个自杀任务来销毁自己的线程
   thread_pool_destroy(tp);	
}

5 编译与执行

在这里插入图片描述

你可能感兴趣的:(linux基础,linux,运维,服务器)