线程池作用及C语言实现

6 篇文章 0 订阅
5 篇文章 0 订阅
本文详细介绍了线程池的作用,包括减少线程创建销毁的开销和实现异步解耦。接着,讨论了线程池中线程数量的确定依据,通常与CPU核心数和任务类型相关。然后,展示了一个简单的C语言线程池实现,包括线程池创建、线程入口函数、任务管理以及线程池销毁。最后,提供了一个完整的线程池代码示例,用于处理和调度任务。
摘要由CSDN通过智能技术生成

一、线程池作用

1.减少线程的创建销毁次数,减少性能开销
当你需要限制你应用程序中同时运行的线程数时,线程池非常有用。因为启动一个新线程会带来性能开销,每个线程也会为其堆栈分配一些内存等。为了任务的并发执行,我们可以将这些任务任务传递到线程池,而不是为每个任务动态开启一个新的线程。

2.异步解耦的作用
以日志系统为例,日志从生成到写入磁盘的主要时间开销在读写IO上,在大量日志需要写入磁盘时,傻傻的等待日志一条一条写入显然是不太科学的。借助线程池,我们可以将任务直接丢给工作线程,由他们去完成这样琐碎的任务,这样就能达到异步解耦的作用。

二、线程池创建数量

线程池中的线程数量是依据什么确定的?
答:参考链接:https://huixxi.github.io/2020/06/02/%E5%B0%8F%E7%99%BD%E8%A7%86%E8%A7%92%EF%BC%9A%E4%B8%80%E6%96%87%E8%AF%BB%E6%87%82%E7%A4%BE%E9%95%BF%E7%9A%84TinyWebServer/#more
线程池中的线程数量最直接的限制因素是中央处理器(CPU)的处理器(processors/cores)的数量N:如果你的CPU是4-cores的,对于CPU密集型的任务(如视频剪辑等消耗CPU计算资源的任务)来说,那线程池中的线程数量最好也设置为4(或者+1防止其他因素造成的线程阻塞);对于IO密集型的任务,一般要多于CPU的核数,因为线程间竞争的不是CPU的计算资源而是IO,IO的处理一般较慢,多于cores数的线程将为CPU争取更多的任务,不至在线程处理IO的过程造成CPU空闲导致资源浪费,公式:最佳线程数 = CPU当前可使用的Cores数 * 当前CPU的利用率 * (1 + CPU等待时间 / CPU处理时间)

二、C语言线程池

下面我们用C写一个基本的线程池,基本功能有线程池创建初始化、任务请求与响应、线程池销毁。

1.首先创建任务相关结构体、工作线程相关结构体与线程池结构体:

// 任务相关结构体
typedef struct _st_Task
{
    void *taskId;
    void (*do_task)(struct _st_Task *); // 处理任务回调函数
    struct _st_Task *prev;
    struct _st_Task *next;
}st_Task;

// 工作线程相关结构体
typedef struct _st_Work
{
    pthread_t pthreadId;
    int shutdown; // 线程终止开关
    struct _st_ThreadPoolQueue *threadPoolQueue;
    struct _st_Work *prev;
    struct _st_Work *next;
}st_Work;

// 线程池结构体
typedef struct _st_ThreadPoolQueue
{
    st_Work *workQueue;
    st_Task *taskQueue;
    pthread_mutex_t mutex;
    pthread_cond_t cond;
}st_ThreadPoolQueue;

线程池结构体包含两个链表,分别是工作线程链表和任务链表,通过一个线程池结构体管理整个线程池的工作。

2.线程池的创建

int createThreadPool(st_ThreadPoolQueue *threadPool, int threadNum)
{
    if(threadPool == NULL)  return -1;
    if(threadNum < 1)   threadNum = 1;
    
    memset(threadPool, 0, sizeof(st_ThreadPoolQueue));
    
    pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
    pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
    memcpy(&threadPool->mutex, &mutex, sizeof(pthread_mutex_t));
    memcpy(&threadPool->cond, &cond, sizeof(pthread_cond_t));

    int i;
    for(i = 0; i < threadNum; ++i)
    {
        st_Work *work = (st_Work*)malloc(sizeof(st_Work));
        if(work == NULL)
        {
            perror("malloc error!\n");
            return i;
        }

        memset(work, 0, sizeof(work));
        work->threadPoolQueue = threadPool;
        int ret = pthread_create(&work->pthreadId, NULL, threadFunc, (void *)work);
        if(ret < 0)
        {
            perror("pthread_create error!\n");
            free(work);
            return i;
        }

        LIST_ADD(work, work->threadPoolQueue->workQueue);
    }

    return 0;
}

3.线程入口函数

void *threadFunc(void *param)
{
    st_Work *work = (st_Work *)param;

    while(1)
    {
        pthread_mutex_lock(&work->threadPoolQueue->mutex);
        while(work->threadPoolQueue->taskQueue == NULL)
        {
            if(work->shutdown == 1) break;
            pthread_cond_wait(&work->threadPoolQueue->cond, &work->threadPoolQueue->mutex);
        }

        if(work->shutdown == 1) 
        {
            pthread_mutex_unlock(&work->threadPoolQueue->mutex);
            break;
        }

        st_Task *task = work->threadPoolQueue->taskQueue;
        if(task != NULL)
        {
            LIST_REMOVE(task, work->threadPoolQueue->taskQueue);
        }

        pthread_mutex_unlock(&work->threadPoolQueue->mutex);
    
        task->do_task(task);
    }

    free(work);
    pthread_exit(NULL);
}

4.线程销毁

void destroyThreadPool(st_ThreadPoolQueue *threadPool)
{
    st_Work *work = NULL;
    for(work = threadPool->workQueue; work != NULL; work = work->next)
    {
        work->shutdown = 1;
    }

    pthread_cond_broadcast(&threadPool->cond);

    threadPool->taskQueue = NULL;
    threadPool->workQueue = NULL;
    pthread_mutex_destroy(&threadPool->mutex);
    pthread_cond_destroy(&threadPool->cond);
}

5.完整代码如下:

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

#define D_MAX_THREAD_NUM    10
#define D_MAX_TASK_NUM      100

// 宏函数定义
#define LIST_ADD(item, list) do{  \
    item->prev = NULL;            \
    item->next = list;            \
    list = item;                  \
}while(0);

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


// 任务相关结构体
typedef struct _st_Task
{
    void *taskId;
    void (*do_task)(struct _st_Task *);
    struct _st_Task *prev;
    struct _st_Task *next;
}st_Task;

// 工作线程相关结构体
typedef struct _st_Work
{
    pthread_t pthreadId;
    int shutdown;
    struct _st_ThreadPoolQueue *threadPoolQueue;
    struct _st_Work *prev;
    struct _st_Work *next;
}st_Work;

// 线程池结构体
typedef struct _st_ThreadPoolQueue
{
    st_Work *workQueue;
    st_Task *taskQueue;
    pthread_mutex_t mutex;
    pthread_cond_t cond;
}st_ThreadPoolQueue;

void *threadFunc(void *param)
{
    st_Work *work = (st_Work *)param;

    while(1)
    {
        pthread_mutex_lock(&work->threadPoolQueue->mutex);
        while(work->threadPoolQueue->taskQueue == NULL)
        {
            if(work->shutdown == 1) break;
            pthread_cond_wait(&work->threadPoolQueue->cond, &work->threadPoolQueue->mutex);
        }

        if(work->shutdown == 1) 
        {
            pthread_mutex_unlock(&work->threadPoolQueue->mutex);
            break;
        }

        st_Task *task = work->threadPoolQueue->taskQueue;
        if(task != NULL)
        {
            LIST_REMOVE(task, work->threadPoolQueue->taskQueue);
        }

        pthread_mutex_unlock(&work->threadPoolQueue->mutex);
    
        task->do_task(task);
    }

    free(work);
    pthread_exit(NULL);
}

static int createThreadPool(st_ThreadPoolQueue *threadPool, int threadNum)
{
    if(threadPool == NULL)  return -1;
    if(threadNum < 1)   threadNum = 1;
    
    memset(threadPool, 0, sizeof(st_ThreadPoolQueue));
    
    pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
    pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
    memcpy(&threadPool->mutex, &mutex, sizeof(pthread_mutex_t));
    memcpy(&threadPool->cond, &cond, sizeof(pthread_cond_t));

    int i;
    for(i = 0; i < threadNum; ++i)
    {
        st_Work *work = (st_Work*)malloc(sizeof(st_Work));
        if(work == NULL)
        {
            perror("malloc error!\n");
            return i;
        }

        memset(work, 0, sizeof(work));
        work->threadPoolQueue = threadPool;
        int ret = pthread_create(&work->pthreadId, NULL, threadFunc, (void *)work);
        if(ret < 0)
        {
            perror("pthread_create error!\n");
            free(work);
            return i;
        }

        LIST_ADD(work, work->threadPoolQueue->workQueue);
    }

    return 0;
}


void doTask(st_Task *task)
{
    if(task == NULL)
    {
        perror("task is NULL\n");
        return;
    }    

    printf("Do taskid = %d, threadid = %d\n", *(int *)task->taskId, pthread_self());

    free(task->taskId);
    free(task);
}

void inTaskQueue(st_ThreadPoolQueue *threadPool, st_Task *task)
{
    pthread_mutex_lock(&threadPool->mutex);

    LIST_ADD(task, threadPool->taskQueue);
    pthread_cond_signal(&threadPool->cond);

    pthread_mutex_unlock(&threadPool->mutex);
}

void destroyThreadPool(st_ThreadPoolQueue *threadPool)
{
    st_Work *work = NULL;
    for(work = threadPool->workQueue; work != NULL; work = work->next)
    {
        work->shutdown = 1;
    }

    pthread_cond_broadcast(&threadPool->cond);

    threadPool->taskQueue = NULL;
    threadPool->workQueue = NULL;
    pthread_mutex_destroy(&threadPool->mutex);
    pthread_cond_destroy(&threadPool->cond);
}

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

    createThreadPool(&threadPool, D_MAX_THREAD_NUM);

    // 创建指定数量的任务
    int i;
    for(i = 0; i < D_MAX_TASK_NUM; ++i)
    {
        st_Task *task = (st_Task *)malloc(sizeof(st_Task));
        if(task == NULL)
        {
            perror("malloc error\n");
            return -1;
        }

        task->taskId = (int *)malloc(sizeof(int));
        *(int *)task->taskId = i;
        task->do_task = doTask;

        inTaskQueue(&threadPool, task);

        sleep(1);
    }

    getchar();
    destroyThreadPool(&threadPool);

    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

阿杰的小鱼塘

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值