基础学习总结——线程池

经常听到线程池的概念,不过在实际工作和项目里没有应用过线程池。线程池可能是作为服务端的开发经常用到的技术架构,所以最近我也通过网络简单的学习了下线程池的概念,稍微理解了线程池的应用场景。

在高并发的服务环境下,存在多个客户端访问服务端相同服务的场景,而传统方式,是为多客户端创建一一对应的处理线程,这在高并发场景下极大的耗费服务端的资源。为了解决这类问题,服务端可使用线程池,为同一服务创建相同的线程队列,这些线程循环处理工作队列中的任务,当有客户端需要这种服务时将增加任务到工作队列中。
在这里插入图片描述

在实际使用上,可能大家只需要知道如何向工作队列中添加任务即可,不过理解线程池其中的处理流程,可以在遇到问题时更快的理解和定位问题所在,下面通过自己写的一个S端的线程池创建的demo,详细介绍下S端的线程池框架。

首先,前面提到过的,使用线程池需要:线程队列,工作队列,线程池节点。下面是三个对应的结构体

//工作队列节点
struct JOB
{
    void (*job_func)(void * args);
    int date;
    struct JOB* pNext;
    struct JOB* pPrev;        
};

//线程队列节点
struct WORKER
{
    int tid;
    struct WORKER* pNext;
    struct WORKER* pPrev;    
};

//线程池节点
struct Manager
{
    struct WORKER* pWorkers;
    struct JOB* pJobs;
    pthread_mutex_t mtx;
    pthred_cond_t cond;
};

/*使用宏定义,实现链表的增加删除节点*/

#define LL_ADD(item, list) \
{
    item->pNext = list; 
    list->pPrev = item;
    list = item;
}
#define LL_DEL(item, list) \
{
    if(item == list)
        item->pNext = item->pPrev = NULL;
    item->pPrev->pNext = item->pNext;
    item->pNext->pPrev = item->pPrev;
}

初始线程池,包括线程池参数和化线程队列

//线程池初始化
int CreatNthreads(Manager* pMgPool, int workerNum)
{
    int i = 0;
    
    if(NULL == pMgPool)
    {
        return -1;
    }
    pMgPool->mtx = PTHREAD_MUTEX_INITIALIZER;
    pMgPool->cond = PTHREAD_COND_INITIALIZER;
    for(i = 0; i < workerNum; i++)
    {
        WORKER* pWorker = NULL;
        malloc(pWorker,sizeof(WORKER));
        pthread_creat(&pWorker->tid, NULL, TaskWorkerCallback, pMgPool);
        LL_ADD(pWorker, pMgPool->pWorkers);
    }
        
}

实现线程池内部线程接口的逻辑

//线程处理回调
void *TaskWorkerCallback(Manager* pMgPool)
{
    JOB* pJob = NULL;
    if(NULL == pMgPool)
    {
        return -1;
    }
    while(1)
    {
        memset(pJob, 0, sizeof(Job));
        pthread_mutex_lock(&pMgPool->mtx);
        while(NULL == pMgPool->pJobs)
            pthread_cond_wait(&pMgPool->cond ,&pMgPool->mtx);
        pJob = pMgPool->pJobs;
        if(pJob)
            LL_DEL(pJob,pMgPool->pJobs);
        pthread_mutex_unlock(&pMgPool->mtx);
        pJob->job_func(pJob->date);
        pJob = NULL;
        free(pJob);
    }
    
}

前端需要调用postJob()接口向后端工作队列添加节点

//工作真正的处理接口
void func(){}
//向工作队列添加节点
void postJob(Manager* pMgPool,int date)
{
    JOB* pJob = NULL;
    malloc(pJob,sizeof(JOB));

    pthread_mutex_lock(&pMgPool->mtx);
    pJob->job_func = func;
    pJob->date = date;
    LL_ADD(pJob,pMgPool->pJobs);
    pthread_mutex_unlock(&pMgPool->mtx);
    pthread_cond_signal(&pMgPool->cond);
}

以上方式实现的工作队列链表是“类栈链表”,及后来的节点,却优先处理。和栈的出栈入栈方式类似,我这里先叫“类栈链表”吧,到这里基本上实现了线程栈的创建和使用流程,具体在根据应用场景,实现func即可;

缺点:如果是需要响应C端的服务,使用线程池可能会影响响应速度。(不需要响应的,比如客户端发起的会导致写硬盘的操作)

优点:高并发场景下,极大降低了S端的性能需求

(以上,均为作者个人理解,如有错误支持,欢迎评论指导)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值