c语言+pthread实现线程池

1.线程池原理

线程池(thread pool)技术是指能够保证所创建的任一线程都处于繁忙状态,而不需要频繁地为了某一任务而创建和销毁线程,因为系统在创建和销毁线程时所耗费的cpu资源很大。如果任务很多,频率很高,为了单一一个任务而起线程而后销线程,那么这种情况效率相当低下的。线程池技术就是用于解决这样一种应用场景而应运而生的。
pthread线程池实现原理,首先创建多个线程组成线程池,其中每个线程都运行一个被阻塞的循环函数,等待管理者线程唤醒,被唤醒的线程通过函数指针来执行用户所指定的函数,其中线程的阻塞和唤醒使用信号量机制。
ps:该项目改编自知乎文章:https://zhuanlan.zhihu.com/p/44971598
ps:笔者在大佬代码的基础上修改了线程池销毁过程,当线程池中的任务未全部完成时,线程池不会被立刻销毁,直到任务全部执行完成。
ps:在提交的任务函数中不要有sleep这种带有线程取消点的函数,否则在sleep过程中,如果调用destroy_tpool会被主线程默认取消。

2.项目结构

请添加图片描述
提供的api有

一、创建线程池,create_tpool

二、销毁线程池,destroy_tpool

三、分派任务,add_task_2_tpool

项目源代码

tpool.h

#ifndef T_POOL
#define T_POOL
 
#include <pthread.h>
#include <ctype.h>
 
typedef struct tpool_work{
   void* (*work_routine)(void*); //function to be called
   void* args;                   //arguments 
   struct tpool_work* next;
}tpool_work_t;
 
typedef struct tpool{
   size_t               shutdown;       //is tpool shutdown or not, 1 ---> yes; 0 ---> no
   size_t               maxnum_thread; // maximum of threads
   pthread_t            *thread_id;     // a array of threads
   tpool_work_t*        tpool_head;     // tpool_work queue
   pthread_cond_t       queue_ready;    // condition varaible
   pthread_mutex_t      queue_lock;     // queue lock
}tpool_t;
 
 
/***************************************************
*@brief:
*       create thread pool
*@args:   
*       max_thread_num ---> maximum of threads
*       pool           ---> address of thread pool
*@return value: 
*       0       ---> create thread pool successfully
*       othres  ---> create thread pool failed
***************************************************/
 
int create_tpool(tpool_t** pool,size_t max_thread_num);
 
/***************************************************
*@brief:
*       destroy thread pool
*@args:
*        pool  --->  address of pool
***************************************************/
void destroy_tpool(tpool_t* pool);
 
/**************************************************
*@brief:
*       add tasks to thread pool
*@args:
*       pool     ---> thread pool
*       routine  ---> entry function of each thread
*       args     ---> arguments
*@return value:
*       0        ---> add ok
*       others   ---> add failed        
**************************************************/
int add_task_2_tpool(tpool_t* pool,void* (*routine)(void*),void* args);
 
#endif//tpool.h

tpool.c

#include "tpool.h"
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
 

int is_taskover(tpool_t *pool){
     if(pool->tpool_head!=NULL)return 0;
     return 1;
} 
static void* work_routine(void* args)
{
   tpool_t* pool = (tpool_t*)args;
   tpool_work_t* work = NULL;
 
   while(1){
        pthread_mutex_lock(&pool->queue_lock);
        while(!pool->tpool_head && !pool->shutdown){ // if there is no works and pool is not shutdown, it should be suspended for being awake
            pthread_cond_wait(&pool->queue_ready,&pool->queue_lock);
        }
 
        if(pool->shutdown){
           pthread_mutex_unlock(&pool->queue_lock);//pool shutdown,release the mutex and exit
           pthread_exit(NULL);
        }
 
        /* tweak a work*/
        work = pool->tpool_head;
        pool->tpool_head = (tpool_work_t*)pool->tpool_head->next;
        pthread_mutex_unlock(&pool->queue_lock);
 
        work->work_routine(work->args);
 
        free(work);
   }
return NULL;
}
 
int create_tpool(tpool_t** pool,size_t max_thread_num)
{
   (*pool) = (tpool_t*)malloc(sizeof(tpool_t));
   if(NULL == *pool){
        printf("in %s,malloc tpool_t failed!,errno = %d,explain:%s\n",__func__,errno,strerror(errno));
        exit(-1);
   }
   (*pool)->shutdown = 0;
   (*pool)->maxnum_thread = max_thread_num;
   (*pool)->thread_id = (pthread_t*)malloc(sizeof(pthread_t)*max_thread_num);
   if((*pool)->thread_id == NULL){
        printf("in %s,init thread id failed,errno = %d,explain:%s",__func__,errno,strerror(errno));
        exit(-1);
   }
   (*pool)->tpool_head = NULL;
   if(pthread_mutex_init(&((*pool)->queue_lock),NULL) != 0){
        printf("in %s,initial mutex failed,errno = %d,explain:%s",__func__,errno,strerror(errno));
        exit(-1);
   }
 
   if(pthread_cond_init(&((*pool)->queue_ready),NULL) != 0){
        printf("in %s,initial condition variable failed,errno = %d,explain:%s",__func__,errno,strerror(errno));
        exit(-1);
   }
 
   for(int i = 0; i < max_thread_num; i++){
        if(pthread_create(&((*pool)->thread_id[i]),NULL,work_routine,(void*)(*pool)) != 0){
           printf("pthread_create failed!\n");
           exit(-1);
        }
   }
return 0;
}
 
int add_task_2_tpool(tpool_t* pool,void* (*routine)(void*),void* args)
{
   tpool_work_t* work,*member;
 
   if(!routine){
        printf("rontine is null!\n");
        return -1;
   }
 
   work = (tpool_work_t*)malloc(sizeof(tpool_work_t));
   if(!work){
        printf("in %s,malloc work error!,errno = %d,explain:%s\n",__func__,errno,strerror(errno));
        return -1;
   }
 
   work->work_routine = routine;
   work->args = args;
   work->next = NULL;
 
   pthread_mutex_lock(&pool->queue_lock);
   member = pool->tpool_head;
   if(!member){
        pool->tpool_head = work;
   }
   else{
        while(member->next){
           member = (tpool_work_t*)member->next;
        }
        member->next =(tpool_work_t*)work;
   }
 
   //notify the pool that new task arrived!
   pthread_cond_signal(&pool->queue_ready);
   pthread_mutex_unlock(&pool->queue_lock);
return 0;
}

void destroy_tpool(tpool_t* pool)
{
   tpool_work_t* tmp_work;
 
   while(pool->shutdown || !is_taskover(pool));
   
   pool->shutdown = 1;
 
   pthread_mutex_lock(&pool->queue_lock);
   pthread_cond_broadcast(&pool->queue_ready);
   pthread_mutex_unlock(&pool->queue_lock);
 
   for(int i = 0; i < pool->maxnum_thread; i++){
        pthread_join(pool->thread_id[i],NULL);
   }
   free(pool->thread_id);
   while(pool->tpool_head){
        tmp_work = pool->tpool_head;
        pool->tpool_head = (tpool_work_t*)pool->tpool_head->next;
        free(tmp_work);
   }
 
   pthread_mutex_destroy(&pool->queue_lock);
   pthread_cond_destroy(&pool->queue_ready);
   free(pool);
}

demo.c

#include "tpool.h"
#include <stdio.h>
#include <unistd.h>
#include <time.h>
 
void* fun(void* args)
{
   int thread = (int)args;
   printf("running the thread of %d\n",thread);
return NULL;
}
 
int main(int argc, char* args[])
{
   tpool_t* pool = NULL;
   if(0 != create_tpool(&pool,5)){
        printf("create_tpool failed!\n");
        return -1;
   }
 
   for(int i = 0; i <= 1000; i++){
        add_task_2_tpool(pool,fun,(void*)i);
   }
   //sleep(2);
   destroy_tpool(pool);
   return 0;
}

线程池完整源码见

https://github.com/trriger/pthreadpool

  • 3
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
当然可以帮你实现一个简单的线程池。下面是一个用C语言实现线程池的示例代码: ```c #include <stdio.h> #include <stdlib.h> #include <pthread.h> #define MAX_THREADS 5 #define MAX_TASKS 10 typedef struct { void (*function)(void* arg); void* arg; } task_t; typedef struct { task_t* tasks; int front; int rear; int count; int size; pthread_mutex_t lock; pthread_cond_t notify_producer; pthread_cond_t notify_consumer; } threadpool_t; void threadpool_init(threadpool_t* pool, int size); void threadpool_destroy(threadpool_t* pool); void threadpool_add_task(threadpool_t* pool, void (*function)(void* arg), void* arg); void threadpool_run(threadpool_t* pool); void* threadpool_worker(void* arg); void task_function(void* arg); void threadpool_init(threadpool_t* pool, int size) { pool->tasks = (task_t*)malloc(sizeof(task_t) * MAX_TASKS); pool->front = 0; pool->rear = 0; pool->count = 0; pool->size = size; pthread_mutex_init(&(pool->lock), NULL); pthread_cond_init(&(pool->notify_producer), NULL); pthread_cond_init(&(pool->notify_consumer), NULL); for (int i = 0; i < size; i++) { pthread_t tid; pthread_create(&tid, NULL, threadpool_worker, (void*)pool); } } void threadpool_destroy(threadpool_t* pool) { free(pool->tasks); pthread_mutex_destroy(&(pool->lock)); pthread_cond_destroy(&(pool->notify_producer)); pthread_cond_destroy(&(pool->notify_consumer)); } void threadpool_add_task(threadpool_t* pool, void (*function)(void* arg), void* arg) { pthread_mutex_lock(&(pool->lock)); while (pool->count == MAX_TASKS) { pthread_cond_wait(&(pool->notify_producer), &(pool->lock)); } pool->tasks[pool->rear].function = function; pool->tasks[pool->rear].arg = arg; pool->rear = (pool->rear + 1) % MAX_TASKS; pool->count++; pthread_cond_signal(&(pool->notify_consumer)); pthread_mutex_unlock(&(pool->lock)); } void threadpool_run(threadpool_t* pool) { for (int i = 0; i < MAX_TASKS; i++) { threadpool_add_task(pool, task_function, (void*)(intptr_t)i); } } void* threadpool_worker(void* arg) { threadpool_t* pool = (threadpool_t*)arg; while (1) { pthread_mutex_lock(&(pool->lock)); while (pool->count == 0) { pthread_cond_wait(&(pool->notify_consumer), &(pool->lock)); } task_t task = pool->tasks[pool->front]; pool->front = (pool->front + 1) % MAX_TASKS; pool->count--; pthread_cond_signal(&(pool->notify_producer)); pthread_mutex_unlock(&(pool->lock)); task.function(task.arg); } return NULL; } void task_function(void* arg) { int task_id = (intptr_t)arg; printf("Task %d: Executing\n", task_id); // 在这里执行任务的具体逻辑 } int main() { threadpool_t pool; threadpool_init(&pool, MAX_THREADS); threadpool_run(&pool); threadpool_destroy(&pool); return 0; } ``` 以上代码实现了一个简单的固定大小的线程池,可以添加任务并由线程池中的线程执行。你可以在 `task_function` 函数中编写具体的任务逻辑,然后通过调用 `threadpool_add_task` 函数将任务添加到线程池中。 请注意,此示例代码仅为演示用途,没有处理线程池的销毁和错误处理等情况。在实际使用中,你可能需要根据自己的需求进行适当的扩展和修改。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值