Linux-C实现线程池

​ 池是一组资源的集合,这组资源在服务器启动之初就被创建和初始化,这称为静态资源分配。它避免了服务器对内核的频繁访问,提高了效率。

​ 常见的池有进程池,线程池,内存池

内存池

​ 先申请一定数量,大小相等的内存块备用。有新的内存需求时,就从内存池中分出一部分内存块,若内存不足则继续申请新的内存。内存池使内存分配效率得到提升

进程池

​ 进程池线先由服务器创建一组子进程,子进程数量应和CPU数量差不多。所有子程序具有相同的属性,运行着同样的代码

线程池

概念

​ 在Linux中线程实际上是由轻量级进程实现的。线程的创建和清理都需要耗费时间和系统资源,当处理高并发时,线程池就有必要引入了。

​ 线程池提升了多线程程序的性能,因为线程池中线程都是现成且可重复使用的。理想的线程池能够合理地动态调节池内线程数量

​ 线程池是典型的生产者消费者同步问题,主程序不定时将任务任务添加到一个队列中。池中多个工作线程同时执行出队操作(需保证同一时刻只能一个线程出队成功)。这时候生产者是主程序(用于生产任务),消费者是工作线程(用于执行任务)

组成结构

​ 线程池主要包括4个部分:

  1. 线程管理器:用于创建并管理线程池
  2. 工作线程:线程池中实际执行任务的线程,在创建线程池后会创建好固定数目的线程在池中
  3. 任务接口:每个任务必须实现的接口。当队列中有任务时,被池中线程执行,把任务抽象成一个接口,可以做到线程池与具体任务无关
  4. 任务队列:用于存放没有处理的任务

应用

​ 主要应用于需要大量线程来完成任务且任务时间较短,例如Web服务器完成网页请求。或者是突发性的大量请求

代码实现

test.h文件:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>

//任务接口(节点)
struct Work {
    void* (*func) (void *arg);
    void *arg;
    Work *next;
};

//线程池中线程执行的回掉函数
void* thread_poll_func(void *arg);

//线程池
struct thread_poll{
    //任务队列
    Work *head;
    //线程指针
    pthread_t *pd;

    //条件变量和锁
    pthread_mutex_t mutex;
    pthread_cond_t cond;

    //线程池是否被销毁
    bool shutdown;

    //线程池中线程的总量
    int pthread_num;
    //当前任务队列中任务数量
    int work_num;

    //初始化函数
    thread_poll(int pthread_num) {
        this -> pthread_num = pthread_num;
        this -> work_num = 0;
        this -> shutdown = 0;
        pthread_mutex_init(&this ->mutex, NULL);
        pthread_cond_init(&this -> cond, NULL);
        this -> head = NULL;
        pd = (pthread_t *)malloc(sizeof(pthread_t) * pthread_num);
        for (int i = 0; i < pthread_num; i++) {
            pthread_create(&this -> pd[i], NULL, thread_poll_func, this);
        }
    }

    //向线程池投递任务
    void add_work(Work *work);

    //销毁线程池
    int del();
};

test.cpp文件:

#include "test.h"

//线程池中线程执行的回掉函数
void* thread_poll_func(void *arg) {
    thread_poll *t = (thread_poll *)arg;
    while(1) {
        //上锁
        pthread_mutex_lock(&t -> mutex);

        //循环等待接收任务
        while(!(t -> work_num) && !(t -> shutdown)) {
            pthread_cond_wait(&t -> cond, &t -> mutex);
        }

        //如果线程池被销毁
        if (t -> shutdown) {
            //解锁并退出线程
            pthread_mutex_unlock(&t -> mutex);
            pthread_exit(0);
        }

        //取出队首任务
        t -> work_num --;
        Work *p = t -> head;
        t -> head = p -> next;

        //解锁
        pthread_mutex_unlock(&t -> mutex);

        //执行任务回掉函数
        (p -> func)(p -> arg);
        //释放该任务空间
        free(p);
    }
}

//向线程池投递任务
void thread_poll::add_work(Work *work) {
    pthread_mutex_lock(&this -> mutex);
    //将任务加入到等待队列
    Work *p = this -> head;
    if (p == NULL) {
        this -> head = work;
    } else {
        while(p -> next != NULL) {
            p = p -> next;
        }
        p -> next = work;
    }
    this -> work_num ++;
    pthread_mutex_unlock(&this -> mutex);

    //唤醒一个等待线程
    pthread_cond_signal(&this -> cond);
}

//销毁线程池
int thread_poll::del() {
    if (this -> shutdown) {
        return -1;
    }
    this -> shutdown = 1;

    //唤醒所有线程
    pthread_cond_broadcast(&this -> cond);

    //等待所有线程结束,避免僵尸线程
    for (int i = 0; i < this -> pthread_num; i++) {
        pthread_join(this -> pd[i], NULL);
    }

    //释放掉所有线程标识符
    free(pd);

    //销毁任务队列的所有任务
    Work *p = this -> head;
    while(p != NULL) {
        p = this -> head;
        this -> head = p -> next;
        free(p);
    }

    //销毁条件变量和锁
    pthread_cond_destroy(&this -> cond);
    pthread_mutex_destroy(&this -> mutex);
    return 0;
}

//任务的回掉函数
void* myfunc(void *arg) {
    printf("%d\n", *(int *)arg);
    return NULL;
}

int main () {
    thread_poll poll(3);
    int *nuu = (int *)malloc(sizeof(int) * 10);
    for (int i = 0; i < 10; i++) {
        nuu[i] = i;
        Work *work = (Work *)malloc(sizeof(Work));
        work -> next = NULL;
        work -> func = myfunc;
        work -> arg = (void *)&nuu[i];
        poll.add_work(work);
    }

    sleep(5);
    poll.del();
    free(nuu);
    return 0;
}

转载请注明出处!!!

如果有写的不对或者不全面的地方 可通过主页的联系方式进行指正,谢谢

猜你喜欢

转载自blog.csdn.net/Ivan_zcy/article/details/88399709