C 线程池

参考 <https://blog.youkuaiyun.com/qq_36359022/article/details/78796784>

参考 <https://www.bilibili.com/video/BV1iJ411S7UA>

看了大概的思路,自己理解着敲一下,然后对比原来代码有些地方不同。

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


#include <pthread.h>

#include <errno.h>

#include <time.h>

#define DEFAULT_TIME 1

typedef struct{
    void* (*function)(void *);
    void *arg;
}threadpoll_task_t;

typedef struct{
    pthread_t thr_maneger;//管理线程
    int thr_maneger_exit;//管理线程状态

    pthread_mutex_t thr_mutex;//线程组
    pthread_t *thr;//线程的锁
    int thr_min_num;//最低
    int thr_max_num;//最高
    int thr_cap_num;//线程数
    int thr_len_num;//线程活跃数

    pthread_mutex_t task_mutex;//任务的锁
    pthread_cond_t task_cond;//任务的条件变量
    threadpoll_task_t *task_queue;//任务队列,环
    int task_cap_num;//任务队列容量
    int task_len_num;//任务队列的任务数
    int task_head_index;//头
    int task_tail_index;//尾
    int task_suicide;//自杀式任务数
}threadpool_t;


void* threadpool_thread(void *arg){
    threadpool_t *pool = (threadpool_t*)arg;

    for(;;){
        pthread_mutex_lock(&pool->task_mutex);
        while(pool->task_len_num <=0 && pool->task_suicide <= 0)
            pthread_cond_wait(&pool->task_cond,&pool->task_mutex);
        
        //如果有自杀式任务,则自杀
        if(pool->task_suicide > 0){
            pool->task_suicide--;
            pthread_mutex_unlock(&pool->task_mutex);
            break;
        }

        //从任务队列中取数据
        void* (*function)(void *);
        void *arg;
        function = pool->task_queue[pool->task_tail_index].function;
        arg = pool->task_queue[pool->task_tail_index].arg;
        pool->task_tail_index = (pool->task_tail_index+1) % pool->task_cap_num;
        pool->task_len_num--;
        pthread_mutex_unlock(&pool->task_mutex);

        //活跃线程数+1
        pthread_mutex_lock(&pool->thr_mutex);
        pool->thr_len_num++;
        pthread_mutex_unlock(&pool->thr_mutex);
        function(arg);

        //活跃线程数-1
        pthread_mutex_lock(&pool->thr_mutex);
        pool->thr_len_num--;
        pthread_mutex_unlock(&pool->thr_mutex);

        //唤醒可能阻塞中的task_add
        pthread_cond_broadcast(&pool->task_cond);
    }

    pthread_exit(NULL);
}

int is_thread_alive(pthread_t tid){
    int kill_rc = pthread_kill(tid,0);
    if(kill_rc == ESRCH){
        return 0;
    }
    return 1;
}

void *threadpoll_admin(void *arg){
    threadpool_t *pool = (threadpool_t*)arg;
    int thr_min_num;
    int thr_max_num;
    int thr_cap_num,new_thr_cap_num;
    int thr_len_num;
    int task_len_num;
    int task_suicide;
    int count,i;
    
    pthread_mutex_lock(&pool->thr_mutex);
    thr_min_num = pool->thr_min_num;
    thr_max_num = pool->thr_max_num;
    pthread_mutex_unlock(&pool->thr_mutex);

    for(;;){
        sleep(DEFAULT_TIME);

        //判断管理线程是否需要退出
        if(pool->thr_maneger_exit == 1){
            break;
        }

        //取数据
        pthread_mutex_lock(&pool->thr_mutex);
        thr_cap_num = pool->thr_cap_num;
        thr_len_num = pool->thr_len_num;
        pthread_mutex_unlock(&pool->thr_mutex);

        pthread_mutex_lock(&pool->task_mutex);
        task_len_num = pool->task_len_num;
        task_suicide = pool->task_suicide;
        pthread_mutex_unlock(&pool->task_mutex);

        printf("pool status "
        ",thr_cap_num=%d "
        ",thr_len_num=%d "
        ",task_len_num=%d "
        ",task_suicide=%d "
        "\n",
        thr_cap_num,thr_len_num,task_len_num,task_suicide);

        //还没自杀完
        if(task_suicide > 0){
            continue;
        }

        //线程活跃数占80%,扩容
        if(thr_len_num >= thr_cap_num * 0.8){//扩容
            new_thr_cap_num = thr_cap_num*2;
            if(new_thr_cap_num>thr_max_num){
                new_thr_cap_num = thr_max_num;
            }
            count = new_thr_cap_num - thr_cap_num;
            if(count <= 0)
                continue;

            pthread_mutex_lock(&pool->thr_mutex);
            pool->thr_cap_num = new_thr_cap_num;
            pthread_mutex_unlock(&pool->thr_mutex);

            for(i=0;i<thr_max_num && count>0;i++){
                //判断是否是自杀线程,回收
                if(pool->thr[i] != 0 && !is_thread_alive(pool->thr[i])){
                    pthread_join(pool->thr[i],NULL);
                    pool->thr[i] = 0;
                }

                //创建线程
                if(pool->thr[i] == 0){
                    pthread_create(&pool->thr[i],NULL,threadpool_thread,(void*)pool);
                    count--;
                }
            }
            continue;
        }

        //线程活跃数占20%,缩容
        if(thr_len_num <= thr_cap_num * 0.2){//缩容
            new_thr_cap_num = thr_cap_num/2;
            if(new_thr_cap_num<thr_min_num){
                new_thr_cap_num = thr_min_num;
            }
            count = thr_cap_num - new_thr_cap_num;

            if(count <= 0)
                continue;

            //缩容
            pthread_mutex_lock(&pool->thr_mutex);
            pool->thr_cap_num = new_thr_cap_num;
            pthread_mutex_unlock(&pool->thr_mutex);

            //自杀式任务数++++++
            pthread_mutex_lock(&pool->task_mutex);
            pool->task_suicide = count;
            pthread_mutex_unlock(&pool->task_mutex);

            //通知所有线程
            pthread_cond_broadcast(&pool->task_cond);
            continue;
        }
    }

    //销毁所有线程
    pthread_mutex_lock(&pool->thr_mutex);
    thr_cap_num = pool->thr_cap_num;
    thr_len_num = pool->thr_len_num;
    pthread_mutex_unlock(&pool->thr_mutex);

    pthread_mutex_lock(&pool->task_mutex);
    pool->task_suicide = thr_cap_num;
    pthread_mutex_unlock(&pool->task_mutex);

    pthread_cond_broadcast(&pool->task_cond);

    for(i=0;i<thr_max_num;i++){
        if(pool->thr[i] != 0){
            pthread_join(pool->thr[i],NULL);
            pool->thr[i] = 0;
        }
    }

}

threadpool_t* threadpool_create(int thr_min_num,int thr_max_num,int task_cap_num){
    threadpool_t *pool = malloc(sizeof(threadpool_t));
    
    pthread_mutex_init(&pool->thr_mutex,NULL);
    pool->thr = malloc(sizeof(pthread_t) * thr_max_num);
    memset(pool->thr,0,sizeof(pthread_t) * thr_max_num);
    pool->thr_min_num = thr_min_num;
    pool->thr_max_num = thr_max_num;
    pool->thr_cap_num = thr_min_num;
    pool->thr_len_num = 0;
    

    pthread_mutex_init(&pool->task_mutex,NULL);
    pthread_cond_init(&pool->task_cond,NULL);
    pool->task_queue = malloc(sizeof(threadpoll_task_t) * task_cap_num);
    pool->task_cap_num = task_cap_num;
    pool->task_len_num = 0;
    pool->task_head_index = 0;
    pool->task_tail_index = 0;
    pool->task_suicide = 0;

    //创建线程
    int i;
    for(i=0;i<pool->thr_cap_num;i++){
        pthread_create(&pool->thr[i],NULL,threadpool_thread,(void*)pool);
    }

    //管理线程
    pthread_create(&pool->thr_maneger,NULL,threadpoll_admin,(void*)pool);

    return pool;
}

int threadpool_add_task(threadpool_t* pool,void* (*function)(void*),void* arg){
    pthread_mutex_lock(&pool->task_mutex);
    
    while(pool->task_len_num >= pool->task_cap_num)
        pthread_cond_wait(&pool->task_cond,&pool->task_mutex);
    
    //添加任务
    pool->task_queue[pool->task_head_index].function = function;
    pool->task_queue[pool->task_head_index].arg = arg;
    pool->task_head_index = (pool->task_head_index+1) % pool->task_cap_num;
    pool->task_len_num++;
    pthread_mutex_unlock(&pool->task_mutex);

    pthread_cond_signal(&pool->task_cond);
}

void threadpool_destroy(threadpool_t* pool){
    pool->thr_maneger_exit = 1;

    pthread_join(pool->thr_maneger,NULL);

    pthread_mutex_lock(&pool->thr_mutex);
    pthread_mutex_destroy(&pool->thr_mutex);
    pthread_mutex_lock(&pool->task_mutex);
    pthread_mutex_destroy(&pool->task_mutex);
    pthread_cond_destroy(&pool->task_cond);

    free(pool->thr);
    free(pool->task_queue);
    free(pool);
}


void* do_something(void*arg){
    time_t t;
    t = time(NULL);
    printf("-- %lu,%s\n",pthread_self(),ctime(&t));
    sleep(2 * DEFAULT_TIME);
    t = time(NULL);
    printf("!! %lu,%s\n",pthread_self(),ctime(&t));
}

int main(){
    threadpool_t* pool = threadpool_create(20,100,200);


    int i;
    for(i=0;i<1000;i++){
        threadpool_add_task(pool,do_something,NULL);
    }

    sleep(20 * DEFAULT_TIME);
    for(i=0;i<50;i++){
        threadpool_add_task(pool,do_something,NULL);
    }

    sleep(20 * DEFAULT_TIME);
    for(i=0;i<1000;i++){
        threadpool_add_task(pool,do_something,NULL);
    }

    threadpool_destroy(pool);
}

 

<think>嗯,用户想了解如何在C语言中实现和使用线程池。我之前已经学过一些多线程编程的知识,但线程池的具体实现可能有点复杂。首先,我需要回忆一下线程池的基本概念。线程池是一种管理多个线程的技术,通过预先创建一组线程来处理任务,避免频繁创建和销毁线程的开销,从而提高性能。 根据提供的引用内容,特别是引用[2]和引用[3],线程池的实现通常涉及两个主要结构体:任务结构体和线程池结构体。任务结构体包含函数指针、参数和指向下一个任务的指针。线程池结构体则需要互斥锁、条件变量、任务队列、线程ID数组以及一些状态变量,比如最大线程数、活跃线程数和关闭标志。 接下来,我需要考虑线程池的工作流程。主线程将任务添加到队列中,而工作线程则从队列中取出任务并执行。这涉及到线程间的同步,所以互斥锁和条件变量是关键。例如,当任务队列为空时,工作线程应该等待条件变量,直到有新任务加入。当添加任务时,需要发送信号通知等待的线程。 然后,我需要详细每个步骤的实现。比如初始化线程池时,要创建指定数量的线程,并让它们执行任务处理函数。任务处理函数会循环等待任务,直到线程池被关闭。添加任务到队列时,必须使用互斥锁保护队列的访问,以防止竞态条件。 用户可能关心的问题包括如何管理线程的生命周期、如何处理任务队列的同步、如何优雅地关闭线程池等。此外,错误处理也是一个重要部分,比如内存分配失败时的处理,或者线程创建失败的情况。 引用[5]提到添加任务的函数需要将任务放入队列并通知一个阻塞的线程。这提示在实现threadpool_add函数时,需要使用pthread_cond_signal或pthread_cond_broadcast来唤醒等待的线程。而线程池的销毁函数需要设置关闭标志,并唤醒所有线程,让它们退出循环,最后回收资源。 另外,线程池的参数配置也很重要,比如最大线程数应该根据系统资源来设定,避免过多线程导致上下文切换频繁,反而降低性能。引用[1]指出线程池可以优化多任务处理程序的性能,所以合理配置参数是关键。 可能还需要考虑任务队列的大小限制,防止内存耗尽。或者实现动态调整线程数量的机制,但根据引用中的结构体,可能这里的实现是固定线程数的,所以需要用户根据需求调整。 最后,测试和调试线程池时需要注意死锁和竞态条件。使用工具如Valgrind或GDB可以帮助检测这些问题。例如,在添加或取出任务时,确保互斥锁的正确使用,避免在持有锁的情况下执行可能导致阻塞的操作。 总结来说,实现线程池需要结构体定义、线程管理、任务队列同步、资源管理以及错误处理等多个方面的考虑。用户可能需要了解每个部分的具体实现细节,以及如何正确使用线程池来优化他们的程序性能。</think>### C语言线程池实现与用法详解 #### 一、线程池核心结构体 线程池实现需定义两个关键结构体: 1. **任务结构体**:存储任务函数指针和参数 ```c typedef struct task { void (*function)(void *); // 函数指针 void *arg; // 参数 struct task *next; // 任务链表指针 } task_t; ``` 2. **线程池结构体**:管理线程池状态 ```c typedef struct threadpool { pthread_mutex_t lock; // 互斥锁 pthread_cond_t cond; // 条件变量 task_t *task_head; // 任务队列头节点 pthread_t *threads; // 线程ID数组 int thread_count; // 最大线程数 int active_count; // 活跃线程数 int shutdown; // 销毁标志(0运行/1销毁) } threadpool_t; ``` #### 二、实现步骤 1. **初始化线程池** ```c threadpool_t *threadpool_create(int count) { threadpool_t *pool = malloc(sizeof(threadpool_t)); pthread_mutex_init(&pool->lock, NULL); pthread_cond_init(&pool->cond, NULL); pool->threads = malloc(count * sizeof(pthread_t)); for(int i=0; i<count; i++){ pthread_create(&pool->threads[i], NULL, worker, pool); } return pool; } ``` 2. **工作线程函数** ```c void *worker(void *arg) { threadpool_t *pool = (threadpool_t *)arg; while(1) { pthread_mutex_lock(&pool->lock); // 等待任务或线程池销毁 while(pool->task_head == NULL && !pool->shutdown) { pthread_cond_wait(&pool->cond, &pool->lock); } if(pool->shutdown) { pthread_mutex_unlock(&pool->lock); pthread_exit(NULL); } // 取出任务 task_t *task = pool->task_head; pool->task_head = task->next; pthread_mutex_unlock(&pool->lock); // 执行任务函数 task->function(task->arg); free(task); } return NULL; } ``` 3. **添加任务函数** ```c int threadpool_add(threadpool_t *pool, void (*func)(void *), void *arg) { task_t *new_task = malloc(sizeof(task_t)); new_task->function = func; new_task->arg = arg; new_task->next = NULL; pthread_mutex_lock(&pool->lock); // 将任务插入链表尾部 if(pool->task_head) { task_t *cur = pool->task_head; while(cur->next) cur = cur->next; cur->next = new_task; } else { pool->task_head = new_task; } pthread_cond_signal(&pool->cond); // 唤醒一个线程 pthread_mutex_unlock(&pool->lock); return 0; } ``` 4. **销毁线程池** ```c void threadpool_destroy(threadpool_t *pool) { pthread_mutex_lock(&pool->lock); pool->shutdown = 1; // 设置关闭标志 pthread_cond_broadcast(&pool->cond); // 唤醒所有线程 pthread_mutex_unlock(&pool->lock); // 等待所有线程退出 for(int i=0; i<pool->thread_count; i++) { pthread_join(pool->threads[i], NULL); } // 释放资源 free(pool->threads); pthread_mutex_destroy(&pool->lock); pthread_cond_destroy(&pool->cond); free(pool); } ``` #### 三、线程池使用示例 ```c // 定义任务函数 void print_number(void *arg) { int num = *(int *)arg; printf("Processing: %d\n", num); free(arg); } int main() { threadpool_t *pool = threadpool_create(4); // 创建4个线程 for(int i=0; i<10; i++) { int *num = malloc(sizeof(int)); *num = i; threadpool_add(pool, print_number, num); } sleep(1); // 等待任务完成 threadpool_destroy(pool); return 0; } ``` #### 四、关键设计要点 1. **线程同步**:使用互斥锁保护任务队列,条件变量实现任务通知机制[^2][^5] 2. **任务队列**:采用链表结构实现先进先出(FIFO)调度策略[^4] 3. **资源管理**:动态内存分配需严格配对释放,避免内存泄漏 4. **优雅退出**:通过shutdown标志控制线程终止流程 #### 五、性能优化方向 1. 动态调整线程数量(根据负载自动扩容/缩容) 2. 实现优先级任务队列 3. 增加任务超时机制 4. 使用无锁队列优化高频任务场景
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值