简易线程池实现
程序中,频繁地调用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; }
队列相当于是一个共享变量,这些子线程会不断地取任务去执行,有任务出队有任务入队,同一个时刻只能有一个任务进行操作。条件变量用来控制线程的睡眠、启动和销毁时机。
执行结果:
只提供大体思路,上面的程序暂时存在一些小问题,待解决