【c++】【线程池】同步队列

【c++】【线程池】同步队列

是基于 半同步/半异步模式 设计实现的 任务Task是一个模板

1 同步队列的设计

可以将其当作一个生产者-消费者模型
往同步队列中添加任务(Put()) 的过程–>理解为生产者
从同步队列中取出任务(Take()) 的过程–>理解为消费者

1属性

1.1设计一个任务队列 list

list 是一个存储任务的队列(同步队列)
Task是 其中需要存储的任务 是一个模板

1.2给出互斥锁 mutex

生产者和消费者之间需要互斥的往任务队列中添加数据和取走数据

1.3 给出条件变量 condition_variable

提供生产者消费者之间的通知机制
生产者生产数据后可以通知 消费者取走数据
消费者消费数据后可以通知 生产者生产数据

1.4 同步队列是否停止 m_stop

可以根据这个bool值来判断是否需要停止同步队列

1.5 任务队列数据

任务上限

2方法(主要)

2.1生产者向同步队列中添加任务

这是一个模板 ,任务的类型不确定。
1.先获取互斥锁当同步队列未停止运行并且 同步队列满了的情况下 等待

  • 生产者阻塞在同步队列的等待队列中
  • 互斥锁获取失败 进入锁等待队列中

2.退出循环后 再次判断同步队列是否停止运行 停止则退出
3.通过完美转发 向同步队列中添加任务
4.通知消费者可以消费数据

  • 整个的执行流程为:
    • 1 处在就绪态的生产者等待cpu调度
    • 2 获得cpu的生产者从内核获得互斥锁,并返回
    • 3 若同步队列未停止运行并且 同步队列满了 生产者同步队列未满的条件变量.wait()阻塞该生产者
    • 4 此时先弃锁,接着放入条件变量的等待队列中
    • 5 当同步队列未满时 退出循环,生产者放入锁等待队列中
    • 6 获得cpu后将任务放入同步队列,并唤醒阻塞在消费者同步队列的条件变量上的消费者 (通知所有等待条件变量的线程,他会唤醒所有因为wait()或者wait_for()等函数而处于阻塞状态的线程)

2.2消费者从同步队列中获取任务

有两种获取任务的方式 一次是获取一个任务,一次是获取全部任务

2.2.1 获取一个任务

1.先获取互斥锁 当同步队列未停止运行并且 同步队列为空的情况下 等待

  • 消费者阻塞在同步队列的等待队列中
  • 互斥锁获取失败 进入锁等待队列中

2.退出循环后 再次判断同步队列是否停止运行 停止则退出
3.从同步队列中取出一个任务 使用传递进来的task保存
4.同步队列取出的任务pop()
5.通知生产者可以生产数据

  • 整个的执行流程为:
    • 1 处在就绪态的消费者等待cpu调度
    • 2 获得cpu的消费者从内核获得互斥锁,并返回
    • 3 若同步队列未停止运行并且 同步队列为空 消费者同步队列未空的条件变量.wait()阻塞该消费者
    • 4 此时先弃锁,接着放入条件变量的等待队列中
    • 5 当同步队列未空时 退出循环,消费者放入锁等待队列中
    • 6 获得cpu后将任务放入同步队列,并唤醒阻塞在生产者同步队列的的条件变量上的生产者 (通知所有等待条件变量的线程,他会唤醒所有因为wait()或者wait_for()等函数而处于阻塞状态的线程)
2.2.2 获取所有任务

1.先获取互斥锁 当同步队列未停止运行并且 同步队列为空的情况下 等待

  • 消费者阻塞在同步队列的等待队列中
  • 互斥锁获取失败 进入锁等待队列中

2.退出循环后 再次判断同步队列是否停止运行 停止则退出
3.从同步队列中通过std::move()取出所有任务使用传递进来的list保存
4.通知生产者可以生产数据

  • 整个的执行流程为:
    • 1 处在就绪态的消费者等待cpu调度
    • 2 获得cpu的消费者从内核获得互斥锁,并返回
    • 3 若同步队列未停止运行并且 同步队列为空 消费者同步队列未空的条件变量.wait()阻塞该消费者
    • 4 此时先弃锁,接着放入条件变量的等待队列中
    • 5 当同步队列未空时 退出循环,消费者放入锁等待队列中
    • 6 获得cpu后将任务放入同步队列,并唤醒阻塞在生产者同步队列的的条件变量上的生产者 (通知所有等待条件变量的线程,他会唤醒所有因为wait()或者wait_for()等函数而处于阻塞状态的线程)

3方法(次要)

3.1停止函数

3.1.1 直接停止函数

先获得锁 接着将m_stop置为true 强行停止 可能会导致同步队列中 任务未执行
接着唤醒阻塞的生产者和消费者

3.1.2 等待停止函数

先获得锁 之后判断同步队列是否为空 不为空等待
接着唤醒阻塞的生产者和消费者

3.2 同步队列的判满函数

调用list对应api

3.3 同步队列的判空函数

调用list对应api

3.4 同步队列元素个数

调用list对应api

这里存在一个问题 当同步队列满了 生产者阻塞在 同步队列为满的条件变量上 并且阻塞的生产者很多时 若此时消费者消费任务很慢 但是同时唤醒多个生产者 添加数据时虽然要获得锁 但是在生产者进入互斥锁的等待队列之后 并未进行再次处理 可能会导致任务添加失败 这里的解决方案是线程池的拒绝策略 后续会大概讲一下

你可能感兴趣的:(c++,c++,java,网络)