c语言-自定义线程池

c语言-自定义线程池

为什么使用线程池

多线程编程时,需要通过多个线程来处理多个任务。如果不经过优化,那么最简单的想法应该是每到来一个任务,就创建一个线程用来处理这个任务,当这个任务处理完毕,就销毁这个线程。但是这个简单的想法会带来大量的时空开销。设想,假如有成百上千个任务,为了处理它们,岂不是要创建和销毁线程成百上千次,这显然是不划算的。为了减小创建和销毁线程的开销,很容易就可以想到利用"池“结构来优化。所谓的“池”结构,就是我们预先创建好多个线程。当有任务到来时,把这些任务存储起来,与此同时,让空闲的线程去选择任务执行它。这就是线程池的大致思想。创建的线程自线程池创建以后就一直存在,直到线程池被销毁为止,这样就避免了重复创建销毁的开销。
 
在这里插入图片描述

线程的执行方式是需要特别注意:

  • 线程的执行: 一些人对于线程池的使用可能有一些误解,它们认为线程池是通过从线程池中选择线程来执行手上的任务。其实更加形象的说法应该是我们将任务放入线程池的任务队列,然后线程池中的线程就会自动竞争执行任务。为了达到这一点,我们可以把任务队列视为临界资源,利用生产者和消费者模型来解决。添加任务的程序是生产者,工作线程是消费者。所以工作线程一共有两种状态
  • 运行态:取到任务以后开始执行。
  • 阻塞态:没取到任务,可能是因为没有获得互斥锁,也可能是因为当前任务队列中没有任务可以执行。

头文件


#ifndef STUDY_THREAD_POOL_H
#define STUDY_THREAD_POOL_H
#include "../structure/task_queue.h"
#include <pthread.h>
// 线程池结构体
typedef  struct threadPool
{
    
    
    // 任务队列
    Queue* taskQ;
    int queueCapacity;  // 容量
    pthread_t managerID;    // 管理者线程ID
    pthread_t* threadIDs;   // 工作的线程IDs
    int minNum;             // 最小线程数量
    int maxNum;             // 最大线程数量
    int busyNum;            // 忙的线程的个数
    int liveNum;            // 存活的线程的个数
    int exitNum;            // 要销毁的线程个数
    pthread_mutex_t mutexPool;  // 锁整个的线程池
    pthread_mutex_t mutexBusy;  // 锁busyNum变量
    pthread_cond_t notEmpty;    // 任务队列是不是空了
    pthread_cond_t notFull;     // 任务队列是不是满了
    int shutdown;           // 是不是要销毁线程池, 销毁为1, 不销毁为0
} ThreadPool ;
// 创建线程池并初始化
ThreadPool* threadPoolCreate(int min, int max, int queueSize);
// 销毁线程池
int threadPoolDestroy(ThreadPool* pool);

// 给线程池添加任务
int threadPoolAdd(ThreadPool* pool, void(*func)(void*), void* arg);
// 获取线程池中工作的线程的个数
int threadPoolBusyNum(ThreadPool* pool);
// 获取线程池中活着的线程的个数
int threadPoolAliveNum(ThreadPool* pool);
void threadPoolWait(ThreadPool *pool);
#endif //STUDY_THREAD_POOL_H

内容实现

#include <malloc.h>
#include "thread_pool.h"
#include  <stdio.h>
#include <unistd.h>

static void threadExit(ThreadPool *pool) {
    
    
    pthread_t tid = pthread_self();
    for (int i = 0; i < pool->maxNum; ++i) {
    
    
        if (pool->threadIDs[i] == tid) {
    
    
            pool->threadIDs[i] = 0;
            printf("threadExit() called, %llu exiting...\n", tid);
            break;
        }
    }
    pthread_exit(NULL);
}

static void *threadPoolFunction(void *arg) {
    
    
    ThreadPool *pool = (ThreadPool *) arg;
    while (1) {
    
    
        pthread_mutex_lock(&pool->mutexPool);//加锁整个线程池
        //如果线程池中没有任务,且线程池没有销毁,那么就等待
        while (pool->taskQ->size == 0 && !pool->shutdown) {
    
    
            // 阻塞工作线程
            pthread_cond_wait(&pool->notEmpty, &pool->mutexPool);
            // 如果线程池要销毁,那么就退出
            if (pool->exitNum > 0) {
    
    
                pool->exitNum--;
                if (pool->liveNum > pool->minNum) {
    
    
                    pool->liveNum--;
                    pthread_mutex_unlock(&pool->mutexPool);
                    threadExit(pool);
                }
            }

        }
        // 判断线程池是否被关闭了
        if (pool->shutdown) {
    
    
            pthread_mutex_unlock(&pool->mutexPool);
            threadExit(pool);
        }
        // 从任务队列中取出一个任务
        Task *task = dequeue(pool->taskQ);
        // 解锁
        pthread_cond_signal(&pool->notFull);
        pthread_mutex_unlock(&pool->mutexPool);
//        printf("thread %llu start working...\n", pthread_self());
        pthread_mutex_lock(&pool->mutexBusy);
        pool->busyNum++;
        pthread_mutex_unlock(&pool->mutexBusy);
        task->function(task->arg);
        free(task->arg);
        task->arg = NULL;
//        printf("thread %llu end working...\n", pthread_self());
        pthread_mutex_lock(&pool->mutexBusy);
        pool->busyNum--;
        pthread_mutex_unlock(&pool->mutexBusy);
    }
    return NULL;
}

static void *manager(void *arg) {
    
    
    ThreadPool *pool = (ThreadPool *) arg;
    while (!pool->shutdown) {
    
    
        // 每隔3s检测一次
        sleep(3);
        // 取出线程池中任务的数量和当前线程的数量
        pthread_mutex_lock(&pool->mutexPool);
        int queueSize = pool->taskQ->size;
        int liveNum = pool->liveNum;//当前存活的线程数
        pthread_mutex_unlock(&pool->mutexPool);

        // 取出忙的线程的数量
        pthread_mutex_lock(&pool->mutexBusy);
        int busyNum = pool->busyNum;
        pthread_mutex_unlock(&pool->mutexBusy);

        // 如果任务的数量大于0,并且存活的线程数小于最大线程数,那么就创建新的线程
        if (queueSize > 0 && liveNum < pool->maxNum) {
    
    
            pthread_mutex_lock(&pool->mutexPool);
            for (int i = 0; i < pool->maxNum && pool->liveNum < pool->maxNum; ++i) {
    
    
                if (pool->threadIDs[i] == 0) {
    
    //找到一个空闲的线程id,创建线程
                    pthread_create(&pool->threadIDs[i], NULL, threadPoolFunction, pool);
                    pool->liveNum++;
                }
            }
            pthread_mutex_unlock(&pool->mutexPool);
        }

        // 销毁线程  忙的线程*2 < 存活的线程数 && 存活的线程>最小线程数
        if (busyNum * 2 < liveNum && liveNum > pool->minNum) {
    
    
            pthread_mutex_lock(&pool->mutexPool);
            pool->exitNum = busyNum; // 要销毁的线程数,空闲线程内部会自动判断是否销毁
            pthread_mutex_unlock(&pool->mutexPool);
            // 唤醒所有空闲线程,让线程自动销毁,一定的数量
            pthread_cond_broadcast(&pool->notEmpty);
        }
    }
    return NULL;
}


ThreadPool *threadPoolCreate(int min, int max, int queueSize) {
    
    
    ThreadPool *pool = (ThreadPool *) malloc(sizeof(ThreadPool));
    pool->minNum = min;
    pool->maxNum = max;
    pool->liveNum = min;
    pool->queueCapacity = queueSize;
    pool->shutdown = 0;
    pool->taskQ = createQueue();
    pool->threadIDs = (pthread_t *) malloc(sizeof(pthread_t) * max);
    pthread_mutex_init(&(pool->mutexPool), NULL);
    pthread_cond_init(&(pool->notFull), NULL);
    if (pthread_mutex_init(&pool->mutexPool, NULL) != 0 ||
        pthread_mutex_init(&pool->mutexBusy, NULL) != 0 ||
        pthread_cond_init(&pool->notEmpty, NULL) != 0 ||
        pthread_cond_init(&pool->notFull, NULL) != 0 )
    {
    
    
        printf("mutex or condition init fail...\n");
        return NULL;
    }

    int i;
    for (i = 0; i < min; i++) {
    
    
        pthread_create(&(pool->threadIDs[i]), NULL, threadPoolFunction, (void *) pool);
    }
    pthread_create(&(pool->managerID), NULL, manager, (void *) pool);
    return pool;
}

// 存活的线程的个数
int threadPoolAliveNum(ThreadPool *pool) {
    
    
    pthread_mutex_lock(&pool->mutexPool);
    int aliveNum = pool->liveNum;
    pthread_mutex_unlock(&pool->mutexPool);
    return aliveNum;
}

// 忙的线程的个数
int threadPoolBusyNum(ThreadPool *pool) {
    
    
    pthread_mutex_lock(&pool->mutexBusy);
    int busyNum = pool->busyNum;
    pthread_mutex_unlock(&pool->mutexBusy);
    return busyNum;
}

//添加任务,成功返回1,失败返回-1
int threadPoolAdd(ThreadPool *pool, void(*func)(void *), void *arg) {
    
    
    pthread_mutex_lock(&pool->mutexPool);//加锁
    // 如果任务队列满了,就等待
    while (pool->taskQ->size == pool->queueCapacity && !pool->shutdown) {
    
    
        // 阻塞生产者线程
        pthread_cond_wait(&pool->notFull, &pool->mutexPool);
    }
    // 判断线程池是否关闭
    if (pool->shutdown) {
    
    
        pthread_mutex_unlock(&pool->mutexPool);
        return -1;
    }
    // 添加任务
    enqueue(pool->taskQ, createTask(func, arg));
    pthread_cond_signal(&pool->notEmpty); // 唤醒一个线程执行任务
    pthread_mutex_unlock(&pool->mutexPool);//解锁
    return 1;
}
// 销毁线程池 成功返回1,失败返回-1
int threadPoolDestroy(ThreadPool *pool) {
    
    
    if (pool == NULL) {
    
    
        return -1;
    }
    // 关闭线程池
    pool->shutdown = 1;
    // 阻塞等待回收管理者线程执行完毕
    pthread_join(pool->managerID, NULL);
    // 唤醒阻塞的所有线程
    pthread_cond_broadcast(&pool->notEmpty);
    // 释放堆内存
    if (pool->taskQ) {
    
    
        destroyQueue(pool->taskQ);
    }
    if (pool->threadIDs) {
    
    
        free(pool->threadIDs);
    }
    pthread_mutex_destroy(&pool->mutexPool);
    pthread_mutex_destroy(&pool->mutexBusy);
    pthread_cond_destroy(&pool->notEmpty);
    pthread_cond_destroy(&pool->notFull);
    free(pool);
    pool = NULL;
    return 1;
}

//等待所有任务完成
void threadPoolWait(ThreadPool *pool) {
    
    
    if (pool == NULL) {
    
    
        return;
    }
    while (pool->taskQ->size > 0||pool->busyNum>0) {
    
    
        sleep(1);
    }
}

猜你喜欢

转载自blog.csdn.net/weixin_45203607/article/details/126810008
今日推荐