基于c++11同步队列

本文介绍了如何使用C++11的新特性,如原子变量、条件变量和互斥锁,创建一个模板化的同步队列,支持生产者和消费者模式。详细展示了构造、析构函数以及主要的成员函数实现,包括Push、Take、Stop等操作。
摘要由CSDN通过智能技术生成

同步队列

介绍

实现过程

介绍

1.本篇文章旨在通过c++11新特新实现基本的参数模板化同步队列,此队列用以支持基本生产者、消费者应用
2.主要通过原子变量、条件变量、互斥锁、链表容器等实现
3.逐步实现此同步队列,并支持基本的生产者、消费者例程

实现过程

变量定义
// 引用使用到的标准库头文件
#include <atomic>              // c++11标准提供原子操作相关,可保证多线程数据访问的安全
#include <condition_variable>  // 条件变量,可用于实现多线程之间的同步操作
#include <list>                // 双向列表队列
#include <mutex>               // c++11标准提供的互斥锁,可用于多线程间数据访问保护操作

template <typename T>    // 参数类型模板化
class SyncQueue          // 同步队列类
{
    ...                  // 省略其它实现
private:
  std::condition_variable m_cv;  // 同步原语
  std::list<T> m_queue;          // 数据队列
  std::mutex m_mutex;            // 互斥锁,保护数据队列多线程访问
  std::atomic_bool m_stop;       // 停止队列,拒绝接收数据
};
成员函数
// 主要提供以下类成员函数
// SyncQueue、~SyncQueue、Push、Take、Stop、Size、IsEmpty等

SyncQueue() : m_stop(false) {}            // 构造函数
  virtual ~SyncQueue() { Stop(true); }    // 析构函数

  void Push(const T &v) {      // 添加数据到类内部数据队列
    if (m_stop)                // 停止添加数据
      return;

    {                          // 减小锁的粒度
      std::lock_guard<std::mutex> locker(m_mutex);   // 保护数据
      m_queue.emplace_back(v);                       // 添加数据
    }
    m_cv.notify_one();    // 通知任意一个其它同步阻塞的线程,有数据可读
  }
  void Push(T &&v) {      // 添加数据到类内部数据队列,形参以右值引用方式传输
    if (m_stop)
      return;

    {
      std::lock_guard<std::mutex> locker(m_mutex);
      m_queue.emplace_back(v);
    }
    m_cv.notify_one();
  }

  void Take(std::list<T> *ret) {     // 获取类内部队列数据,一次获取所有
    if (ret == nullptr)              // 判断是否空指针
        return;

    {
      std::unique_lock<std::mutex> locker(m_mutex);

      // 同步阻塞当前线程,当通知后唤醒线程,继续执行之后的流程,若lambda函数返回 false,则继续阻塞当前线程
      m_cv.wait(locker, [this] { return m_stop || !m_queue.empty(); });   
    }

    if (m_stop)
      return;

    std::lock_guard<std::mutex> locker(m_mutex);
    ret->swap(m_queue);    // 获取所有数据
  }
  void Take(T *ret) {      // 获取某一个数据
    if (ret == nullptr)
        return;

    {
      std::unique_lock<std::mutex> locker(m_mutex);
      m_cv.wait(locker, [this] { return m_stop || !m_queue.empty(); });
    }

    if (m_stop)
      return;

    std::lock_guard<std::mutex> locker(m_mutex);
    *ret = m_queue.front();           // 获取第一个数据
    m_queue.erase(m_queue.begin());   // 删除已获取的数据
  }

  bool Stop(bool stop) {   // 停止队列
    m_stop.store(stop);
    if (m_stop)
      m_cv.notify_all();   // 唤醒所有同步等待线程
  }
  int Size() {             // 获取队列数据数量
    std::lock_guard<std::mutex> locker(m_mutex);
    return m_queue.size();
  }
  bool IsEmpty() {         // 判断队列是否为空
    std::lock_guard<std::mutex> locker(m_mutex);
    return m_queue.empty();
  }
完整实现
// SyncQueue.hpp

#ifndef SYNCQUEUE_H
#define SYNCQUEUE_H

#include <atomic>
#include <condition_variable>
#include <list>
#include <mutex>

namespace que {

template <typename T> class SyncQueue {
public:
  SyncQueue() : m_stop(false) {}
  virtual ~SyncQueue() { Stop(true); }

  void Push(const T &v) {
    if (m_stop)
      return;

    {
      std::lock_guard<std::mutex> locker(m_mutex);
      m_queue.emplace_back(v);
    }
    m_cv.notify_one();
  }
  void Push(T &&v) {
    if (m_stop)
      return;

    {
      std::lock_guard<std::mutex> locker(m_mutex);
      m_queue.emplace_back(v);
    }
    m_cv.notify_one();
  }
  void Take(std::list<T> *ret) {
    if (ret == nullptr)
      return;

    {
      std::unique_lock<std::mutex> locker(m_mutex);
      m_cv.wait(locker, [this] { return m_stop || !m_queue.empty(); });
    }

    if (m_stop)
      return;

    std::lock_guard<std::mutex> locker(m_mutex);
    ret->swap(m_queue);
  }
  void Take(T *ret) {
    if (ret == nullptr)
      return;

    {
      std::unique_lock<std::mutex> locker(m_mutex);
      m_cv.wait(locker, [this] { return m_stop || !m_queue.empty(); });
    }

    if (m_stop)
      return;

    std::lock_guard<std::mutex> locker(m_mutex);
    *ret = m_queue.front();
    m_queue.erase(m_queue.begin());
  }

  bool Stop(bool stop) {
    m_stop.store(stop);
    if (m_stop)
      m_cv.notify_all();
  }
  int Size() {
    std::lock_guard<std::mutex> locker(m_mutex);
    return m_queue.size();
  }
  bool IsEmpty() {
    std::lock_guard<std::mutex> locker(m_mutex);
    return m_queue.empty();
  }

private:
  std::condition_variable m_cv;
  std::list<T> m_queue;
  std::mutex m_mutex;
  std::atomic_bool m_stop;
};

} // namespace que

#endif // SYNCQUEUE_H

}
例程
  • 生产者、消费者模式,数据同步
#include "SyncQueue.hpp"
#include <thread>
#include <chrono>
#include <iostream>

void TestSyncQueue() {
  que::SyncQueue<int> sync;
  std::thread t1([&sync] {
    thread_local int i = 0;
    while (true) {
      sync.Push(std::move(i++));
      std::this_thread::sleep_for(std::chrono::milliseconds(500));
    }
  });

  std::thread t2([&sync] {
    int val = -1;
    while (true) {
      sync.Take(&val);
      std::cout << val << " - " << std::this_thread::get_id() << std::endl;
      std::this_thread::sleep_for(std::chrono::milliseconds(500));
    }
  });

  std::thread t3([&sync] {
    int val = -1;
    while (true) {
      sync.Take(&val);
      std::cout << val << " - " << std::this_thread::get_id() << std::endl;
      std::this_thread::sleep_for(std::chrono::milliseconds(500));
    }
  });

  std::thread t4([&sync] {
    int val = -1;
    while (true) {
      sync.Take(&val);
      std::cout << val << " - " << std::this_thread::get_id() << std::endl;
      std::this_thread::sleep_for(std::chrono::milliseconds(500));
    }
  });

  t1.join();
  t2.join();
  t3.join();
  t4.join();
}

int main(int argc, char *argv[]) {
  TestSyncQueue();
  return 0;
}

输出结果:

0 - 139746321880640

1 - 139746330273344

2 - 139746313487936

3 - 139746321880640

4 - 139746330273344

5 - 139746330273344

6 - 139746321880640

7 - 139746321880640

8 - 139746330273344

9 - 139746313487936

10 - 139746321880640

  • 异步任务模式

#include "SyncQueue.hpp"
#include <functional>
...

using Task = std::function<void()>;   // 函数包装器,抽象任务类型
class ExecuteTask final {
public:
  ...

  void Push(const Task &task) {
    m_queue.Push(task);
  }
  void Push(Task &&task) {
    m_queue.Push(task);
  }

private:
  que::SyncQueue<Task> m_queue;

  // std::thread* m_thread;   // 此处使用线程或线程池,同步等待任务,异步执行
};

起始

  • 6
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值