【池式组件】线程池的原理与实现

news2025/1/11 8:17:46

线程池的原理与实现

  • 线程池简介
    • 1.线程池
    • 1.线程池
    • 2.数量固定的原因
    • 3.线程数量如何确定
    • 4.为什么需要线程池
    • 5.线程池结构
  • 线程池的实现
    • 数据结构设计
      • 1.任务结构
      • 2.任务队列结构
      • 3.线程池结构
    • 接口设计
  • 线程池的应用
    • reactor
    • redis 中线程池
    • skynet 中线程池

线程池简介

1.线程池

1.线程池

一种管理维持固定线程数量的池式结构。

2.数量固定的原因

  • 避免频繁的创建和销毁线程,造成资源浪费
  • 随着线程的数量不断增多,并不能实现性能的提升,相反可能造成系统负担

3.线程数量如何确定

  • CPU密集型:proc(CPU核心数)
  • IO密集型(网络IO,磁盘IO):2 * proc(CPU核心数)

4.为什么需要线程池

某类任务执行特别耗时,造成阻塞,严重影响该线程执行其他任务
作用:

  • 复用线程资源;
  • 减少线程创建和销毁的开销;
  • 可异步处理生产者线程的任务;
  • 减少了多个任务(不是一个任务)的执行时间;

5.线程池结构

线程池属于一种生产消费模型。
线程池运行环境构成:
生产者线程:发布任务
队列:存储任务,调度线程池
消费者线程:取出任务,执行任务

线程池的实现

数据结构设计

1.任务结构

typedef struct task_s {
    void *next;
    handler_pt func;
    void *arg;
} task_t;

2.任务队列结构

typedef struct task_queue_s {
    void *head;
    void **tail; 
    int block;
    spinlock_t lock;
    pthread_mutex_t mutex;
    pthread_cond_t cond;
} task_queue_t;

3.线程池结构

struct thrdpool_s {
    task_queue_t *task_queue;
    atomic_int quit;
    int thrd_count;
    pthread_t *threads;
};

接口设计


// 创建对象的时候,回滚式的
static task_queue_t *
__taskqueue_create() {
    task_queue_t *queue = (task_queue_t *)malloc(sizeof(*queue));
    if (!queue) return NULL;

    int ret;
    ret = pthread_mutex_init(&queue->mutex, NULL);
    if (ret == 0) {
        ret = pthread_cond_init(&queue->cond, NULL);
        if (ret == 0) {
            spinlock_init(&queue->lock);
            queue->head = NULL;
            queue->tail = &queue->head;
            queue->block = 1;
            return queue;
        }
        pthread_cond_destroy(&queue->cond);
    }
    pthread_mutex_destroy(&queue->mutex);
    return NULL;
}

static void
__nonblock(task_queue_t *queue) {
    pthread_mutex_lock(&queue->mutex);
    queue->block = 0;
    pthread_mutex_unlock(&queue->mutex);
    pthread_cond_broadcast(&queue->cond);
}

static inline void 
__add_task(task_queue_t *queue, void *task) {
    void **link = (void **)task; // malloc 
    *link = NULL; // task->next = NULL;
    spinlock_lock(&queue->lock);
    *queue->tail = link;
    queue->tail = link;
    spinlock_unlock(&queue->lock);
    pthread_cond_signal(&queue->cond);
}

static inline void * 
__pop_task(task_queue_t *queue) {
    spinlock_lock(&queue->lock);
    if (queue->head == NULL) {
        spinlock_unlock(&queue->lock);
        return NULL;
    }
    task_t *task;
    task = queue->head;
    queue->head = task->next;
    if (queue->head == NULL) {
        queue->tail = &queue->head;
    }
    spinlock_unlock(&queue->lock);
    return task;
}

static inline void * 
__get_task(task_queue_t *queue) {
    task_t *task;
    // 虚假唤醒
    while ((task = __pop_task(queue)) == NULL) {
        pthread_mutex_lock(&queue->mutex);
        if (queue->block == 0) {
            // break;
            pthread_mutex_unlock(&queue->mutex);
            return NULL;
        }
        // 1. 先 unlock(&mtx);
        // 2. 在 cond 休眠
        // ----- 生产者产生任务  signal
        // 3. 在 cond 唤醒
        // 4. 加上  lock(&mtx);
        pthread_cond_wait(&queue->cond, &queue->mutex);
        pthread_mutex_unlock(&queue->mutex);
    }
    return task;
}

static void
__taskqueue_destroy(task_queue_t *queue) {
    task_t *task;
    while ((task = __pop_task(queue))) { // 任务的生命周期由 thrdpool 管理
        free(task);
    }
    spinlock_destroy(&queue->lock);
    pthread_cond_destroy(&queue->cond);
    pthread_mutex_destroy(&queue->mutex);
    free(queue);
}

static void *
__thrdpool_worker(void *arg) {
    thrdpool_t *pool = (thrdpool_t*) arg;
    task_t *task;
    void *ctx;

    while (atomic_load(&pool->quit) == 0) {
        task = (task_t*)__get_task(pool->task_queue);
        if (!task) break;
        handler_pt func = task->func;
        ctx = task->arg;
        free(task);
        func(ctx);
    }
    
    return NULL;
}

static void 
__threads_terminate(thrdpool_t * pool) {
    atomic_store(&pool->quit, 1);
    __nonblock(pool->task_queue);
    int i;
    for (i=0; i<pool->thrd_count; i++) {
        pthread_join(pool->threads[i], NULL);
    }
}

static int 
__threads_create(thrdpool_t *pool, size_t thrd_count) {
    pthread_attr_t attr;
	int ret;

    ret = pthread_attr_init(&attr);
    if (ret == 0) {
        pool->threads = (pthread_t *)malloc(sizeof(pthread_t) * thrd_count);
        if (pool->threads) {
            int i = 0;
            for (; i < thrd_count; i++) {
                if (pthread_create(&pool->threads[i], &attr, __thrdpool_worker, pool) != 0) {
                    break;
                }
            }
            pool->thrd_count = i;
            pthread_attr_destroy(&attr);
            if (i == thrd_count)
                return 0;
            __threads_terminate(pool);
            free(pool->threads);
        }
        ret = -1;
    }
    return ret;
}

void
thrdpool_terminate(thrdpool_t * pool) {
    atomic_store(&pool->quit, 1);
    __nonblock(pool->task_queue);
}

thrdpool_t *
thrdpool_create(int thrd_count) {
    thrdpool_t *pool;

    pool = (thrdpool_t*) malloc(sizeof(*pool));
    if (!pool) return NULL;

    task_queue_t *queue = __taskqueue_create();
    if (queue) {
        pool->task_queue = queue;
        atomic_init(&pool->quit, 0);
        if (__threads_create(pool, thrd_count) == 0) {
            return pool;
        }
        __taskqueue_destroy(pool->task_queue);
    }
    free(pool);
    return NULL;
}

int
thrdpool_post(thrdpool_t *pool, handler_pt func, void *arg) {
    if (atomic_load(&pool->quit) == 1) {
        return -1;
    }
    task_t *task = (task_t *)malloc(sizeof(task_t));
    if (!task) return -1;
    task->func = func;
    task->arg = arg;
    __add_task(pool->task_queue, task);
    return 0;
}

void
thrdpool_waitdone(thrdpool_t *pool) {
    int i;
    for (i=0; i<pool->thrd_count; i++) {
        pthread_join(pool->threads[i], NULL);
    }
    __taskqueue_destroy(pool->task_queue);
    free(pool->threads);
    free(pool);
}

线程池的应用

reactor

在这里插入图片描述
在一个事件循环中,可以处理多个就绪事件,这些就绪事件在reactor 模型中时串行执行的,一个事件处理若耗时较长,会延迟其他同时触发的事件的处理(对于客户端而言,响应会变得较慢)。

redis 中线程池

在这里插入图片描述
作用:读写 io 处理以及数据包解析、压缩;

skynet 中线程池

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1295184.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ABP vNext 扩展 CurrentUser

ABP内置Users表&#xff0c;我们可以对其字段进行扩展&#xff0c;辅助进行更详细的数据记录 ICurrentUser 是主要的服务,用于获取有关当前活动的用户信息. 以下是 ICurrentUser 接口的基本属性:1. IsAuthenticated 如果当前用户已登录(已认证),则返回 true. 如果用户尚未登录…

软件设计师——面向对象技术(一)

&#x1f4d1;前言 本文主要是【面向对象技术】——软件设计师—面向对象技术的文章&#xff0c;如果有什么需要改进的地方还请大佬指出⛺️ &#x1f3ac;作者简介&#xff1a;大家好&#xff0c;我是听风与他&#x1f947; ☁️博客首页&#xff1a;CSDN主页听风与他 &#…

每日一练2023.12.8—— 稳赢【PTA】

题目链接&#xff1a; L1-044 稳赢 题目要求&#xff1a; 大家应该都会玩“锤子剪刀布”的游戏&#xff1a;两人同时给出手势&#xff0c;胜负规则如图所示&#xff1a; 现要求你编写一个稳赢不输的程序&#xff0c;根据对方的出招&#xff0c;给出对应的赢招。但是&#xff…

正则表达式(7):转义符

正则表达式&#xff08;7&#xff09;&#xff1a;正则表达式&#xff08;5&#xff09;&#xff1a;转义符 本博文转载自 此处&#xff0c;我们来认识一个常用符号&#xff0c;它就是反斜杠 “\” 反斜杠有什么作用呢&#xff1f;先不着急解释&#xff0c;先来看个小例子。 …

Python random模块及用法

random 模块主要包含生成伪随机数的各种功能变量和函数。 在 Python 的交互式解释器中先导入 random 模块&#xff0c;然后输入 random.__all__ 命令&#xff08;__all__ 变量代表了该模块开放的公开接口&#xff09;&#xff0c;即可看到该模块所包含的全部属性和函数&#x…

【分享】我想上手机器学习

目录 前言 一、理解机器学习 1.1 机器学习的目的 1.2 机器学习的模型 1.3 机器学习的数据 二、学习机器学习要学什么 2.1 学习机器学习的核心内容 2.2 怎么选择模型 2.3 怎么获取训练数据 2.4 怎么训练模型 三、机器学习的门槛 3.1 机器学习的第一道门槛 3.2 机器…

ES-环境安装(elasticsearch:7.17.9,kibana,elasticsearch-head)

ES 环境搭建 1 拉取镜像 常用三件套 docker pull kibana:7.17.9 docker pull elasticsearch:7.17.9 docker pull mobz/elasticsearch-head:52 启动镜像 elasticsearch 安装 这里可以先不挂载文件启动一波&#xff0c;然后把容器里的文件拷贝出来 docker run -p 19200:9200 …

[oeasy]python0002_终端_CLI_GUI_编程环境_游戏_真实_元宇宙

回忆 上次 了解了 python 语言的特点 历史悠久功能强大深受好评已成趋势 3大主流操作系统 macwindowslinux 我们 选择 linux 作为基础系统 为什么选择 黑乎乎的命令行界面呢&#xff1f;&#x1f914; GUI vs CLI 个人电脑 用图标和菜单组成 图形界面(GUI) Graphic User I…

Numpy数组的重塑,转置与切片 (第6讲)

Numpy数组的重塑,转置与切片 (第6讲)         🍹博主 侯小啾 感谢您的支持与信赖。☀️ 🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ�…

朴素贝叶斯 朴素贝叶斯原理

朴素贝叶斯 朴素贝叶斯原理 判别模型和生成模型 监督学习方法又分生成方法 (Generative approach) 和判别方法 (Discriminative approach)所学到的模型分别称为生成模型 (Generative Model) 和判别模型 (Discriminative Model)。 朴素贝叶斯原理 朴素贝叶斯法是典型的生成学习…

鸿蒙OS应用开发之最简单的程序

鸿蒙OS应用开发之最简单的程序 前面介绍怎么样安装鸿蒙应用开发的环境&#xff0c;然后试着运行起来&#xff0c;并安装运行的虚拟机&#xff0c;以及对应9.0版本的API和SDK等软件。这样就具备了基本的开发基础&#xff0c;就可以进入创建应用程序开发了。 在我们起飞之前&…

【Java基础系列】Cron表达式入门

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

通过kubeadm方式安装k8s

虚拟机最少是 2 core&#xff0c;master内存最小3G&#xff0c;node内存最小2G. 要求的Docker版本是18.03&#xff0c;如果不是安装的docker ce&#xff0c;版本是过旧的&#xff0c;可以选择删除后重新安装&#xff1b; 也可以重新创建一个虚拟机执行以下命令。 简单方法&am…

解决“使用command+shift+a 总是弹出默认终端”

冲突出现的终端如下 问题原因 MacOS下使用IntelliJ 系列的IDE就是经常遇到这个问题&#xff0c;原因该快捷键与系统的 《在“终端”中搜索man页面索引 》功能的快捷键冲突了&#xff0c;Find Action是一个很高频使用的&#xff01; 解决方案 把系统《在“终端”中搜索man…

5组10个共50个音频可视化效果PR音乐视频制作模板

我们常常看到的图形跟着音乐跳动&#xff0c;非常有节奏感&#xff0c;那这个是怎么做到的呢&#xff1f;5组10个共50个音频可视化效果PR音乐视频制作模板满足你的制作需求。 PR音乐模板|10个音频可视化视频制作模板05 https://prmuban.com/36704.html 10个音频可视化视频制作…

Python语言求解嵌套列表中的最大元素和

更多资料获取 &#x1f4da; 个人网站&#xff1a;ipengtao.com 在处理嵌套列表时&#xff0c;有时我们需要找到列表中的最大元素以及对应的位置。本文将深入讨论如何使用Python有效地解决这个问题。我们将使用不同的方法&#xff0c;包括递归、列表推导和NumPy库&#xff0c;…

我有才打造私域流量的知识付费小程序平台

在当今数字化时代&#xff0c;知识付费市场正在迅速崛起&#xff0c;而私域流量的概念也日益受到重视。私域流量指的是企业通过自有渠道获取的、能够自由支配的流量&#xff0c;这种流量具有更高的用户粘性和转化率。因此&#xff0c;打造一个基于私域流量的知识付费小程序平台…

VBA_MF系列技术资料1-237

MF系列VBA技术资料 为了让广大学员在VBA编程中有切实可行的思路及有效的提高自己的编程技巧&#xff0c;我参考大量的资料&#xff0c;并结合自己的经验总结了这份MF系列VBA技术综合资料&#xff0c;而且开放源码&#xff08;MF04除外&#xff09;&#xff0c;其中MF01-04属于定…

防水,也不怕水。Mate X5是如何做到让你湿手湿屏也不影响操作的?

相信不少人都碰到过当手机屏幕存在小水珠时&#xff0c;触控变得不灵敏&#xff0c;或者出现“幽灵触屏”&#xff0c;指东打西的情况。 尤其是在洗澡、做饭&#xff0c;或者在户外遇到下雨天气时&#xff0c;如果打湿的手机收到重要聊天消息或者电话&#xff0c;却因为湿屏导…

Hazel引擎学习(十二)

我自己维护引擎的github地址在这里&#xff0c;里面加了不少注释&#xff0c;有需要的可以看看 参考视频链接在这里 Scene类重构 参考&#xff1a;《InsideUE4》GamePlay架构&#xff08;二&#xff09;Level和World 目前我的Scene类基本只是给entt的封装&#xff0c;提供了…