池式结构-线程池


在多线程的操作中,我们经常使用线程池来进行大量的计算、缓存磁盘、写log等。线程池主要由 任务队列执行队列管理组件。三部分组成。如图,中间的框框就是我们的线程池,threadqueue负责从taskqueue取任务,当没有任务时,thread通过条件变量进行等待。处理完成之后,返回处理的结果。
在这里插入图片描述

任务队列

typedef struct job {
    void (*func)(struct job *arg); 
    void *userdata;

    struct job *prev;
    struct job *next;
}job_t;

任务队列主要主要有回调处理函数,和用户数据、前指针和后指针组成。

执行队列

typedef struct work {
    pthread_t thread;
    int treminate;
    struct workqueue *threadpool;

    struct work *prev;
    struct work *next;
}work_t;

执行队列就是我们的threadqueue。 主要有线程id, terminate标志可以使线程退出,线程池的指针、前指针和后指针组成。

管理组件

typedef struct workqueue{
    struct work *works;
    struct job  *jobs;

    pthread_cond_t jobs_cond;
    pthread_mutex_t jobs_mutex;
}threadpool;

管理组件就是我们的线程池了,也就是对任务队列和执行队列进行加锁,通知等。

基本组件了解之后,我们就要对线程池进行创建、任务分配、销毁等。

创建线程池

int ThreadPoolCreate(threadpool *pool, int numWorks) {
    if(numWorks < 1) numWorks = 1;
    memset(pool, 0, sizeof(threadpool));

    pthread_cond_t blank_cond = PTHREAD_COND_INITIALIZER;
    pthread_mutex_t bland_mutex = PTHREAD_MUTEX_INITIALIZER;

    memcpy(&pool->jobs_cond, &blank_cond, sizeof(pool->jobs_cond));
    memcpy(&pool->jobs_mutex, &bland_mutex, sizeof(pool->jobs_mutex));

    for (int i = 0; i < numWorks; ++i) {
        work_t *worker =  (work_t *)calloc(1, sizeof(work_t));
        if(worker == NULL) {
            perror("calloc");
            return -1;
        }
        worker->threadpool = pool;

        int ret = pthread_create(&worker->thread, NULL, ThreadFunc, (void *)worker);
        
        if(ret) {
            perror("pthread_create");
            free(worker);
            return -1;
        }

        LL_ADD(worker, worker->threadpool->works);
    }

    return 0;
}

线程池的创建也很简单,主要对条件变量和互斥锁进行初始化。对每个任务进行创建线程,并加入到threadqueue中。创建完线程之后,线程就开始运行了。

线程运行

static void *ThreadFunc(void *arg) {
    work_t *worker = (work_t*)arg;
    printf("pid :%u, tid: %ld, self: %lu\n", getpid(), (long int)syscall(__NR_gettid), pthread_self());
    while(1) {
        pthread_mutex_lock(&worker->threadpool->jobs_mutex);

        while(worker->threadpool->jobs == NULL) {
            if(worker->treminate) break;
            pthread_cond_wait(&worker->threadpool->jobs_cond, &worker->threadpool->jobs_mutex);
        }
        if(worker->treminate) break;

        job_t *jober = worker->threadpool->jobs;
        if(jober != NULL) {
            LL_REMOVE(jober, worker->threadpool->jobs);
        }
        pthread_mutex_unlock(&worker->threadpool->jobs_mutex);

        if(jober == NULL) continue;

        jober->func(jober);
    }
    free(worker);
    pthread_exit(NULL);
}

在线程里面,我们主要就是取任务,如果没有任务,我们就等待,如果有设置terminate, 我们就退出。取到了任务之后,我们就执行任务队列的回调函数。

任务回调函数

static void client(job_t *arg) {
    int index = *(int*)arg->userdata;

    printf("index: %d, selfid: %lu\n", index, pthread_self());

    free(arg->userdata);
    free(arg);
}

我们的任务处理函数很简单,主要对传进来的参数进行读取。

整个code:

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

 #include <sys/types.h>
 #include <sys/syscall.h>


#define LL_ADD(item, list) do { \
        item->prev = NULL;      \
        item->next = list;      \
        list = item;            \
}while(0)

#define LL_REMOVE(item, list) do {  \
        if(item->prev != NULL) item->prev->next = item->next;   \
        if(item->next != NULL) item->next->prev = item->prev;   \
        if(item == list) list = item->next;                     \
        item->prev = item->next = NULL;                         \
}while(0)


typedef struct work {
    pthread_t thread;
    int treminate;
    struct workqueue *threadpool;

    struct work *prev;
    struct work *next;
}work_t;

typedef struct job {
    void (*func)(struct job *arg); 
    void *userdata;

    struct job *prev;
    struct job *next;
}job_t;

typedef struct workqueue{
    struct work *works;
    struct job  *jobs;

    pthread_cond_t jobs_cond;
    pthread_mutex_t jobs_mutex;
}threadpool;

static void *ThreadFunc(void *arg) {
    work_t *worker = (work_t*)arg;
    printf("pid :%u, tid: %ld, self: %lu\n", getpid(), (long int)syscall(__NR_gettid), pthread_self());
    while(1) {
        pthread_mutex_lock(&worker->threadpool->jobs_mutex);

        while(worker->threadpool->jobs == NULL) {
            if(worker->treminate) break;
            pthread_cond_wait(&worker->threadpool->jobs_cond, &worker->threadpool->jobs_mutex);
        }
        if(worker->treminate) break;

        job_t *jober = worker->threadpool->jobs;
        if(jober != NULL) {
            LL_REMOVE(jober, worker->threadpool->jobs);
        }
        pthread_mutex_unlock(&worker->threadpool->jobs_mutex);

        if(jober == NULL) continue;

        jober->func(jober);
    }
    free(worker);
    pthread_exit(NULL);
}

int ThreadPoolCreate(threadpool *pool, int numWorks) {
    if(numWorks < 1) numWorks = 1;
    memset(pool, 0, sizeof(threadpool));

    pthread_cond_t blank_cond = PTHREAD_COND_INITIALIZER;
    pthread_mutex_t bland_mutex = PTHREAD_MUTEX_INITIALIZER;

    memcpy(&pool->jobs_cond, &blank_cond, sizeof(pool->jobs_cond));
    memcpy(&pool->jobs_mutex, &bland_mutex, sizeof(pool->jobs_mutex));

    for (int i = 0; i < numWorks; ++i) {
        work_t *worker =  (work_t *)calloc(1, sizeof(work_t));
        if(worker == NULL) {
            perror("calloc");
            return -1;
        }
        worker->threadpool = pool;

        int ret = pthread_create(&worker->thread, NULL, ThreadFunc, (void *)worker);
        
        if(ret) {
            perror("pthread_create");
            free(worker);
            return -1;
        }

        LL_ADD(worker, worker->threadpool->works);
    }

    return 0;
}

void ThreadPoolDestory(threadpool *pool){
    work_t *worker = NULL;

    for(worker = pool->works; worker != NULL; worker = worker->next) {
        worker->treminate = 1;
    }
    pthread_mutex_lock(&pool->jobs_mutex);

    pool->works = NULL;
    pool->jobs = NULL;

    pthread_cond_broadcast(&pool->jobs_cond);
    pthread_mutex_unlock(&pool->jobs_mutex);
}

static void client(job_t *arg) {
    int index = *(int*)arg->userdata;

    printf("index: %d, selfid: %lu\n", index, pthread_self());

    free(arg->userdata);
    free(arg);
}

void ThreadPoolQueue(threadpool *pool, job_t *job) {
    pthread_mutex_lock(&pool->jobs_mutex);

    LL_ADD(job, pool->jobs);

    pthread_cond_signal(&pool->jobs_cond);
    pthread_mutex_unlock(&pool->jobs_mutex);
} 

int main(int argc, char **argv) {
    threadpool pool;
    if(argc < 1) {
        printf("usage:%d\n", argc);
        return -1;
    }
    int numworks = atoi(argv[1]);

    ThreadPoolCreate(&pool, numworks);
    for(int i = 0; i < numworks; ++i) {
        job_t *jober = (job_t*)calloc(1, sizeof(job_t));
        if(jober == NULL) {
            perror("calloc");
            return -1;
        }

        jober->func = client;
        jober->userdata = calloc(1, sizeof(int));
        *(int *)jober->userdata = i;
        ThreadPoolQueue(&pool, jober);       
    }
    getchar();
	printf("\n");
    
    //ThreadPoolDestory(&pool->thread);
    return 0;
}

code2:

threadpool.h

#include <pthread.h>

struct job
{
    void* (*callback_function)(void *arg);    //线程回调函数
    void *arg;                                //回调函数参数
    struct job *next;
};

struct threadpool
{
    int thread_num;                   //线程池中开启线程的个数
    int queue_max_num;                //队列中最大job的个数
    struct job *head;                 //指向job的头指针
    struct job *tail;                 //指向job的尾指针
    pthread_t *pthreads;              //线程池中所有线程的pthread_t
    pthread_mutex_t mutex;            //互斥信号量
    pthread_cond_t queue_empty;       //队列为空的条件变量
    pthread_cond_t queue_not_empty;   //队列不为空的条件变量
    pthread_cond_t queue_not_full;    //队列不为满的条件变量
    int queue_cur_num;                //队列当前的job个数
    int queue_close;                  //队列是否已经关闭
    int pool_close;                   //线程池是否已经关闭
};

//================================================================================================
//函数名:                   threadpool_init
//函数描述:                 初始化线程池
//输入:                    [in] thread_num     线程池开启的线程个数
//                         [in] queue_max_num  队列的最大job个数 
//输出:                    无
//返回:                    成功:线程池地址 失败:NULL
//================================================================================================
struct threadpool* threadpool_init(int thread_num, int queue_max_num);

//================================================================================================
//函数名:                    threadpool_add_job
//函数描述:                  向线程池中添加任务
//输入:                     [in] pool                  线程池地址
//                          [in] callback_function     回调函数
//                          [in] arg                     回调函数参数
//输出:                     无
//返回:                     成功:0 失败:-1
//================================================================================================
int threadpool_add_job(struct threadpool *pool, void* (*callback_function)(void *arg), void *arg);

//================================================================================================
//函数名:                    threadpool_destroy
//函数描述:                   销毁线程池
//输入:                      [in] pool                  线程池地址
//输出:                      无
//返回:                      成功:0 失败:-1
//================================================================================================
int threadpool_destroy(struct threadpool *pool);

//================================================================================================
//函数名:                    threadpool_function
//函数描述:                  线程池中线程函数
//输入:                     [in] arg                  线程池地址
//输出:                     无  
//返回:                     无
//================================================================================================
void* threadpool_function(void* arg);

threadpool.cpp

#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdarg.h>
#include <sys/time.h>
#include <unistd.h>
#include <iostream>
#include <sstream>
#include "threadpool.h"

using namespace std;



#define TASK_NUMBER 100

struct threadpool *threadpool_init(int thread_num, int queue_max_num)
{
    struct threadpool *pool = NULL;
    do
    {
        pool = (struct threadpool *)malloc(sizeof(struct threadpool));
        if (NULL == pool)
        {
            printf("failed to malloc threadpool!\n");
            break;
        }
        pool->thread_num = thread_num;
        pool->queue_max_num = queue_max_num;
        pool->queue_cur_num = 0;
        pool->head = NULL;
        pool->tail = NULL;
        if (pthread_mutex_init(&(pool->mutex), NULL))
        {
            printf("failed to init mutex!\n");
            break;
        }
        if (pthread_cond_init(&(pool->queue_empty), NULL))
        {
            printf("failed to init queue_empty!\n");
            break;
        }
        if (pthread_cond_init(&(pool->queue_not_empty), NULL))
        {
            printf("failed to init queue_not_empty!\n");
            break;
        }
        if (pthread_cond_init(&(pool->queue_not_full), NULL))
        {
            printf("failed to init queue_not_full!\n");
            break;
        }
        pool->pthreads = (pthread_t *)malloc(sizeof(pthread_t) * thread_num);
        if (NULL == pool->pthreads)
        {
            printf("failed to malloc pthreads!\n");
            break;
        }
        pool->queue_close = 0;
        pool->pool_close = 0;
        int i;
        for (i = 0; i < pool->thread_num; ++i)
        {
            pthread_create(&(pool->pthreads[i]), NULL, threadpool_function, (void *)pool);
        }

        return pool;
    } while (0);

    return NULL;
}

int threadpool_add_job(struct threadpool *pool, void *(*callback_function)(void *arg), void *arg)
{
    assert(pool != NULL);
    assert(callback_function != NULL);
    assert(arg != NULL);

    pthread_mutex_lock(&(pool->mutex));
    while ((pool->queue_cur_num == pool->queue_max_num) && !(pool->queue_close || pool->pool_close))
    {
        pthread_cond_wait(&(pool->queue_not_full), &(pool->mutex)); //队列满的时候就等待
    }
    if (pool->queue_close || pool->pool_close) //队列关闭或者线程池关闭就退出
    {
        pthread_mutex_unlock(&(pool->mutex));
        return -1;
    }
    struct job *pjob = (struct job *)malloc(sizeof(struct job));
    if (NULL == pjob)
    {
        pthread_mutex_unlock(&(pool->mutex));
        return -1;
    }
    pjob->callback_function = callback_function;
    pjob->arg = arg;
    pjob->next = NULL;
    if (pool->head == NULL)
    {
        pool->head = pool->tail = pjob;
        pthread_cond_broadcast(&(pool->queue_not_empty)); //队列空的时候,有任务来时就通知线程池中的线程:队列非空
    }
    else
    {
        pool->tail->next = pjob;
        pool->tail = pjob;
    }
    pool->queue_cur_num++;
    pthread_mutex_unlock(&(pool->mutex));
    return 0;
}

static uint64_t get_tick_count()
{
    struct timeval tval;
    uint64_t ret_tick;

    gettimeofday(&tval, NULL);

    ret_tick = tval.tv_sec * 1000L + tval.tv_usec / 1000L;
    return ret_tick;
}

void *threadpool_function(void *arg)
{
    struct threadpool *pool = (struct threadpool *)arg;
    struct job *pjob = NULL;
    uint64_t start_time = get_tick_count();
    uint64_t end_time = get_tick_count();
    while (1) //死循环
    {
        pthread_mutex_lock(&(pool->mutex));
        while ((pool->queue_cur_num == 0) && !pool->pool_close) //队列为空时,就等待队列非空
        {
            end_time = get_tick_count();    // 没有任务的时候设置读取最后处理任务的时间
            printf("threadpool need time:%lums\n", end_time - start_time);
            pthread_cond_wait(&(pool->queue_not_empty), &(pool->mutex));
        }
        if (pool->pool_close) //线程池关闭,线程就退出
        {
            pthread_mutex_unlock(&(pool->mutex));
            pthread_exit(NULL);
        }
        pool->queue_cur_num--;
        pjob = pool->head;
        if (pool->queue_cur_num == 0)
        {
            pool->head = pool->tail = NULL;
        }
        else
        {
            pool->head = pjob->next;
        }
        if (pool->queue_cur_num == 0)
        {
            pthread_cond_signal(&(pool->queue_empty)); //队列为空,就可以通知threadpool_destroy函数,销毁线程函数
        }
        if (pool->queue_cur_num == pool->queue_max_num - 1)
        {
            pthread_cond_broadcast(&(pool->queue_not_full)); //队列非满,就可以通知threadpool_add_job函数,添加新任务
        }
        pthread_mutex_unlock(&(pool->mutex));

        (*(pjob->callback_function))(pjob->arg); //线程真正要做的工作,回调函数的调用
        free(pjob);
        pjob = NULL;
    }
}
int threadpool_destroy(struct threadpool *pool)
{
    assert(pool != NULL);
    pthread_mutex_lock(&(pool->mutex));
    if (pool->queue_close || pool->pool_close) //线程池已经退出了,就直接返回
    {
        pthread_mutex_unlock(&(pool->mutex));
        return -1;
    }

    pool->queue_close = 1; //置队列关闭标志
    while (pool->queue_cur_num != 0)
    {
        pthread_cond_wait(&(pool->queue_empty), &(pool->mutex)); //等待队列为空
    }

    pool->pool_close = 1; //置线程池关闭标志
    pthread_mutex_unlock(&(pool->mutex));
    pthread_cond_broadcast(&(pool->queue_not_empty)); //唤醒线程池中正在阻塞的线程
    pthread_cond_broadcast(&(pool->queue_not_full));  //唤醒添加任务的threadpool_add_job函数
    int i;
    for (i = 0; i < pool->thread_num; ++i)
    {
        pthread_join(pool->pthreads[i], NULL); //等待线程池的所有线程执行完毕
    }

    pthread_mutex_destroy(&(pool->mutex)); //清理资源
    pthread_cond_destroy(&(pool->queue_empty));
    pthread_cond_destroy(&(pool->queue_not_empty));
    pthread_cond_destroy(&(pool->queue_not_full));
    free(pool->pthreads);
    struct job *p;
    while (pool->head != NULL)
    {
        p = pool->head;
        pool->head = p->next;
        free(p);
    }
    free(pool);
    return 0;
}



// #define random(x) (rand()%x)

static string int2string(uint32_t user_id)
{
    stringstream ss;
    ss << user_id;
    return ss.str();
}

int main(int argc, char *argv[])
{

    thread_num = atoi(argv[1]);


    printf("thread_num = %d,\n", thread_num);
    struct threadpool *pool = threadpool_init(thread_num, TASK_NUMBER); // 初始化线程
    for (int i = 0; i < TASK_NUMBER; i++)
    {
        if (use_pool)       // 使用连接池时任务采用workUsePool
        {
            threadpool_add_job(pool, work, (void *)pDBPool);
        }
        else                // 不使用连接池时任务采用workNoPool
        {
            threadpool_add_job(pool, work, (void *)pDBPool);
        }
    }

    while(pool->queue_cur_num !=0 )     // 判断队列是否还有任务
    {
         sleep(1);  // 还有任务主线程继续休眠
    }
    sleep(2);       // 没有任务要处理了休眠2秒退出,这里等待主要是确保所有线程都已经空闲
    threadpool_destroy(pool);

    delete pDBPool;
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值