简易线程池实现

程序中,频繁地调用pthread_create函数创建线程,非常浪费时间,尤其在服务器端的时候,多线程的使用情况下频繁启用线程和释放线程资源,这样也会影响程序的运行效率。

可以先在服务器空闲的时候先创建多个线程,我们先在线程函数里面使用pthread_cond_wait将其休眠,有任务过来的时候使用pthread_cond_signal启用线程。

 

多线程(2)-线程同步条件变量 - lethe1203 - 博客园 (cnblogs.com)一节demo中,使用条件变量和Mutex实现生产者和消费者模型,有一点很关键:

pthread_cond_wait函数里面发生了什么?  --释放了互斥锁,pthread_cond_wait函数里面第二个参数是互斥锁

生产者线程如果没有通知消费者线程,消费者线程就无法把锁unlock,这样也保证了生产者线程对临界区的唯一性访问

 

这也就是下面简易线程池的核心所在:

threadpool.h

#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>
 
// queue node
typedef struct Task 
{
        void (*function)(void *arg);                                                                 
        void *arg;
        struct Task *next;
} Task;
 
typedef struct ThreadPool
{
        Task *queueFront;
        Task *queueRear;
 
        int num;
 
        pthread_t *threadID;
 
        pthread_mutex_t mutex;
 
        pthread_cond_t cond;
 
        // shutdown pool
        int shutdown;
} ThreadPool;

 

threadpool.c

#include "threadpool.h"
 
void *worker(void *arg)
{
        ThreadPool *pool = (ThreadPool *)arg;
        while (1) 
        {
                pthread_mutex_lock(&pool->mutex);
 
                // 如果任务队列为空,且线程池没有被关闭,线程睡眠
                while (pool->queueFront == pool->queueRear && pool->shutdown == 0)
                {
                        // 阻塞等待任务
                        pthread_cond_wait(&pool->cond, &pool->mutex);
                }
 
                if (pool->shutdown == 1) {
                        printf("--------------------debug8\n");                        
                        pthread_mutex_unlock(&pool->mutex);
                        printf("thread shutdown thread %ld exit ...\n", pthread_self());
                        pthread_exit((void *)0);
                }
 
                Task task;
                Task *t = pool->queueFront->next;
                task.function = t->function;
                task.arg = t->arg;
                pool->queueFront->next = t->next;
                free(t);
 
                if (pool->queueFront->next == NULL) {
                        pool->queueRear = pool->queueFront;
                }
 
                pthread_mutex_unlock(&pool->mutex);
 
                printf("thread %ld start working ...\n", pthread_self());
                task.function(task.arg);        // 函数指针调用函数
                printf("thread %ld end working ...\n", pthread_self());
        }
}
 
ThreadPool *create_thread_pool(int num)
{
        // printf("--------------------debug1");
        ThreadPool *pool = (ThreadPool *)malloc(sizeof(ThreadPool));
        if (pool == NULL) {
                printf("malloc threadpool memory failed\n");
                return NULL;
        }
        // printf("--------------------debug2");
 
        pool->queueFront = (Task *)malloc(sizeof(Task));
        if (pool->queueFront == NULL) {
                fprintf(stderr, "malloc Task failed\n");
                goto pfree;
                return NULL;
        }
 
        // printf("--------------------debug3");
        // pool->queueRear = pool->queueFront;
        pool->queueFront->next =  NULL;
        pool->queueRear = pool->queueFront;
 
        pool->num = num;
        // printf("--------------------debug4");
 
        // init threadid
        pool->threadID = (pthread_t *)malloc(sizeof(pthread_t) * num);
        if (pool->threadID == NULL) {
                fprintf(stderr, "malloc threadID failed\n");
                goto qfree;
                return NULL;
        }
 
        // printf("--------------------debug5");
        for (int i = 0; i < num; i++) {
                if (pthread_create(&pool->threadID[i], NULL, worker, pool) != 0)
                {
                        fprintf(stderr, "pthread_create threadID failed\n");
                        goto tfree;
                        return NULL;
                }
                pthread_detach(pool->threadID[i]);        // pthread detach
        }
 
        // printf("--------------------debug6");
        pthread_mutex_init(&pool->mutex, NULL);
        pthread_cond_init(&pool->cond, NULL);
 
        pool->shutdown = 0;        // 0: running 1: shutsown
 
        return pool;
pfree:
        free(pool);
        return 0;
qfree:
        free(pool->queueFront);
        free(pool);
        return 0;
tfree:
        free(pool->threadID);
        free(pool->queueFront);
        free(pool);
        return 0;
}
 
void taskfunction(void *arg)
{
        int num = *(int *)arg;
        printf("thread %ld is working num = %d ...\n", pthread_self(), num);
 
        sleep(1);
 
        free(arg);
        // return 0;
}
 
void thread_pool_add(ThreadPool *pool, void (*func)(void *), void *arg)
{
        pthread_mutex_lock(&pool->mutex);
 
        Task *t = (Task *)malloc(sizeof(Task));
        if (t == NULL) {
                fprintf(stderr, "malloc Task failure\n");
                return;
        }
 
        // 一个任务包含三个部分,线程函数,参数,指向下一个任务节点的指针
        t->function = func;
        t->arg = arg;
        t->next = NULL;
        
        pool->queueRear->next = t;
        pool->queueRear = t;
        pthread_mutex_unlock(&pool->mutex);
 
        pthread_cond_signal(&pool->cond);
}
 
void thread_pool_destroy(ThreadPool *pool)
{
        // 关闭线程池
        pool->shutdown = 1;
 
        printf("--------------------debug7\n");
        // 唤醒所有线程
        for (int i = 0; i < pool->num; i++) {
                pthread_cond_signal(&pool->cond);
        }
 
        // 释放线程号
        if (pool->threadID) {
                free(pool->threadID);
        }
 
        // 释放任务队列
        while (pool->queueFront->next)
        {
                Task *t = pool->queueFront->next;
                pool->queueFront->next = t->next;
                free(t);
        }
 
        free(pool->queueFront);
 
        // 释放互斥锁和条件变量
        pthread_mutex_destroy(&pool->mutex);
        pthread_cond_destroy(&pool->cond);
 
        // 释放线程池
        free(pool);
}
 
int main()
{
        ThreadPool *pool = create_thread_pool(10);
        if (pool == NULL) {
                printf("create thread pool failed\n");
                return -1;
        }
 
        printf("threadPool create success.\n");
 
        sleep(1);
 
        for (int i = 0; i < 5; i++) {
                int *n = (int *)malloc(sizeof(int));
 
                *n = i;
 
                // 将任务添加到任务队列,taskfunction任务函数
                thread_pool_add(pool, taskfunction, n);
        }
        sleep(6);
 
        thread_pool_destroy(pool);
 
        return 0;
}

队列相当于是一个共享变量,这些子线程会不断地取任务去执行,有任务出队有任务入队,同一个时刻只能有一个任务进行操作。条件变量用来控制线程的睡眠、启动和销毁时机。

 

执行结果:

 

只提供大体思路,上面的程序暂时存在一些小问题,待解决

 

posted @ 2024-04-04 08:11  lethe1203  阅读(15)  评论(0编辑  收藏  举报