• 工作线程池实现(一) c++版思路


        在某些时候,系统中的一些任务可以并行操作来提高性能,此时如果频繁的创建&销毁线程又会造成大量地开销,因此需要借助线程池来操作。

    (一)功能

    • 添加任务到线程池
    • 获取任务执行结果
    • 维护线程池中线程状态

    (二)设计思路

    • 生产者&消费者模式

    任务队列: 生产者与消费者公用的资源

    生产者   : 将请求分解为多个小任务,并将其放入任务队列

    消费者   : 线程池中的工作线程从任务队列中取任务进行处理

    • 等待任务执行完毕

    1)如何获得任务执行的结果?

    将任务执行结果结构体的指针作为参数传给任务队列,在任务执行后直接将结果写到对应位置。

    2)将任务A拆分为A1、A2、A3、A4、A5放入任务队列,如何知道任务已执行完毕?

    对每个请求维护任务计数,当新增任务时计数++,当任务执行完毕时计数--;在每个请求后条件等待直到计数为0,表明该请求的任务执行完毕。

    • 确定线程池 线程数&任务队列size

    1)根据目前服务请求量计算线程个数

    2)任务队列尽量设置够大

    3)根据实际情况调整线程数

    (三)结构

    • 线程池管理

    初始化若干工作线程&销毁工作线程

    • 工作线程

    如果队列不空,从人物队列取任务&执行任务

    • 上层请求线程

    拆分请求为多个任务&依次放入任务队列&等待任务完成&任务结果

    • 任务队列

    存放&提取任务,控制任务的先进先出

    (四)数据结构

    • 任务结构
    序号 成员 类型 含义
    1 *function(void*, void*, int) 函数指针 指向任务函数的指针
    2 *argument void* 指向任务函数参数的指针
    3 *control_task control_task_t 控制任务计数的结构变量
    4 task_type int 任务类型(根据不同类型,实现不同的任务)
    • 任务计数控制(control_task_t)
    序号 成员 类型 含义
    1 task_count_mutex pthread_mutex_t 控制未完成任务计数的互斥锁
    2 task_count_cond pthread_cond_t 控制等待任务完成的条件锁
    3 unfinished_task_count int 未完成任务计数
    • 线程池
    序号 成员 类型 含义
    1 lock pthread_mutex_t 控制任务队列的互斥锁
    2 notify pthread_cont_t 控制任务队列的条件锁
    3 threads pthread_t* 工作线程
    4 queue threadpool_task_t* 任务队列
    5 thread_count int 工作线程数量
    6 queue_size int 任务队列大小
    7 head int 队头
    8 tail int 队尾
    9 count int pending任务数
    10 shutdown int 关闭线程池标记
    11 started int 运行工作线程
    • 异常状态处理
      含义
    threadpool_invalid -1 线程池无效
    threadpool_lock_failure -2 线程池加锁失败
    threadpool_queue_full -3 任务队列满
    thread_shutdown -4 线程池已关闭
    threadpool_thread_failture -5 销毁线程时join线程失败


    (五)实现

    1)添加任务(threadpool_add)

    互斥锁->任务结构入队尾->条件信号->解锁

    2)工作线程(*threadpool_thread(void *threadpool))

    取任务:锁->条件等队列不空->从队头取出任务->解锁

    执行任务:(*function)(argument,control_task,task_type)

    3)创建线程池(threadpool* threadpool_create(thread_count,queue_size,flag))

    4)销毁线程池(threadpool_destroy(*pool,flags))

    标记置位,等待所有工作线程执行完毕

    (六)使用

    1)任务分解&入任务队列

    锁->未完成任务数++->解锁->threadpool_add放入任务

    • 为什么要在放入任务前进行++操作,而不是放入后?

    在放入后执行++操作可能造成计数不一致

    2)任务实现

    在任务执行完后,未完成任务数-- -> 如果未完成任务数==0,发送信号

    3)搜集任务结果

    锁->如果未完成任务数>0,则条件等待 ->解锁

    (七)总结&优化

    • 减小锁粒度

    所有请求使用一个锁 => 每个请求拥有自己的锁

    • 减小锁范围

    锁addTask和count++ => 调整操作顺序,只锁count++

  • 相关阅读:
    线程同步的三种方式(Mutex,Event,Critical Section) 沧海
    VC++多线程下内存操作的优化 沧海
    C++内存对象大会战 沧海
    技术关注:搜索引擎经验 沧海
    jira 3.13.5版 安装 配置 用户权限控制 拂晓风起
    C++ int string 转换 拂晓风起
    C++调用C链接库会出现的问题 拂晓风起
    Windows Server 2003 IIS Service Unavailable 问题解决 拂晓风起
    研究 学术 开发 的好用工具(不包括常见的) 拂晓风起
    SGMarks 问世 (Firefox扩展Gmarks的扩展版) 纯属学习 拂晓风起
  • 原文地址:https://www.cnblogs.com/taoxinrui/p/6041194.html
Copyright © 2020-2023  润新知