首页 > 编程语言 >安全线程队列 — C++

安全线程队列 — C++

时间:2024-10-10 14:22:03浏览次数:7  
标签:std 队列 lk C++ Base 线程 shared mQueue event

一、安全队列

#pragma once
#include <queue>
#include <memory>
#include <mutex>
#include <condition_variable>

template <typename T>
class SafeQueue
{
private:
    mutable std::mutex mMutex;
    std::queue<T> mQueue;
    std::condition_variable mCond;

public:
    SafeQueue() {}
    SafeQueue(SafeQueue const &other)
    {
        std::lock_guard<std::mutex> lk(other.mMutex);
        mQueue = other.mQueue;
    }

    void push(T new_value)
    {
        std::lock_guard<std::mutex> lk(mMutex);
        mQueue.push(new_value);
        mCond.notify_one();
    }

    void waitAndPop(T &value)
    {
        std::unique_lock<std::mutex> lk(mMutex);
        mCond.wait(lk, [this]() { return !mQueue.empty(); });
        value = mQueue.front();
        mQueue.pop();
    }

    std::shared_ptr<T> waitAndPop()
    {
        std::unique_lock<std::mutex> lk(mMutex);
        mCond.wait(lk, [this]()  { return !mQueue.empty(); });
        std::shared_ptr<T> res(std::make_shared<T>(mQueue.front()));
        mQueue.pop();
        return res;
    }

    bool tryPop(T &value)
    {
        std::lock_guard<std::mutex> lk(mMutex);
        if (mQueue.empty())
            return false;
        value = mQueue.front();
        mQueue.pop();
        return true;
    }

    std::shared_ptr<T> tryPop()
    {
        std::lock_guard<std::mutex> lk(mMutex);
        if (mQueue.empty())
            return std::shared_ptr<T>();
        std::shared_ptr<T> res(std::make_shared<T>(mQueue.front()));
        mQueue.pop();
        return res;
    }

    bool empty() const
    {
        std::lock_guard<std::mutex> lk(mMutex);
        return mQueue.empty();
    }
};

二、安全队列一般使用在多线程调用,容易出现调用错乱,为了能同步调用,把每一个回调都根据先后顺序放在一个安全队列中执行

三、举例使用安全队列
在一个类中有多个回调通知。

enum class ManagerEventType
{
    NOTIFY_Base_1_RESULT,
    NOTIFY_Base_2_Begin,
    NOTIFY_Base_3_END,
};

struct Slot
{
    std::string area;
    std::string key;
    std::string value;
};

struct ManagerEvent
{
    ManagerEventType eventType;
    Slot slot;
    bool status;
};

class Manager : public RESULTCallback, 
                public BeginCallback, 
                public ENDCallback
{
public:
 // 初始化mInitThreadExit标志位线程队列是否退出
Manager::Manager()
    : mInitThreadExit(false),
      mEventQueue(),
      mWorkThread(nullptr) {

}

// 初始化的时候执行这个同步线程。
void AISpeechManager::init()
{
    VLOGD("AISpeechManager::init() -> start");
    mWorkThread = std::make_shared<std::thread>(&AISpeechManager::workLoop, this);
}
 
AISpeechManager::~AISpeechManager()
{
    if (mInitThreadExit == false) {
        mInitThreadExit = true;
          // 等待线程执行结束之后再退出,joinable检测是否用过join,没有用过在使用join
        if ((mWorkThread != nullptr) && (mWorkThread->joinable())) {
            mWorkThread->join();
        }
    }
}

private:
   Slot mslot;
   std::atomic<bool> mInitThreadExit{false};
   SafeQueue<ManagerEvent> mEventQueue;
   std::shared_ptr<std::thread> mWorkThread;

private:

   // 异步通知过来先统一扔进安全队列中等待上一个执行结束之后会通知先一个调用执行
   void resulte() {
         mslot.area = "学号"
          mslot.key = "123"
          mslot.value = "liming"
          ManagerEvent event;
          event.eventType = ManagerEventType::NOTIFY_Base_1_RESULT;
          event.slot= mslot;
          sendEvent(event);
    }
    
    void beginSts(bool beginSts){
          ManagerEvent event;
          event.eventType = ManagerEventType::NOTIFY_Base_2_Begin;
          event.status = begin;
          sendEvent(event);
    }
    void end(){
          ManagerEvent event;
          event.eventType = ManagerEventType::NOTIFY_Base_3_end;
          event.status = begin;
          sendEvent(event);
   }
   
    void sendEvent(ManagerEvent event) {
       mEventQueue.push(event);
    }
    
    void workLoop() {
       while (!mInitThreadExit) {
        ManagerEvent event;
        VLOGD("Manager Begin wait for event");
        mEventQueue.waitAndPop(event);
        VLOGD("Manager Receive event:%d", event.eventType);
        switch (event.eventType) {
            // 在下面case中执行扔进线程队列中的方法要做的事情
            case ManagerEventType::NOTIFY_Base_2_Begin: { 
                if (event.status) {
                    // status is ture do something
                } else {
                    // status is false do something
                }
            }
            case ManagerEventType::NOTIFY_Base_1_RESULT: { 
                 Slot slot = event.slot;
                 // do something
            }
            case ManagerEventType::NOTIFY_Base_3_end:{ 
                 // do something
            }
    }
}

标签:std,队列,lk,C++,Base,线程,shared,mQueue,event
From: https://www.cnblogs.com/kn-zheng/p/18456280

相关文章

  • 通用线程池2
    1publicenumCommonThreadPoolEnum{23TAKE_PHONE_NUMBER_THREAD_POOL;45privateThreadPoolExecutorexecutor;67CommonThreadPoolEnum(){8intcorePoolSize=6;9intmaximumPoolSize=6;10intworkQue......
  • 实验1 现代c++基础编程
    任务1:源代码task1.cpp//现代C++标准库、算法库体验//本例用到以下内容://1.字符串string,动态数组容器类vector、迭代器//2.算法库:反转元素次序、旋转元素//3.函数模板、const引用作为形参#include<iostream>#include<string>#include<vector>#include......
  • 实验1 c++
    任务1:task1.cpp1#include<iostream>2#include<string>3#include<vector>4#include<algorithm>56usingnamespacestd;78//声明9//模板函数声明10template<typenameT>11voidoutput(constT&c);1213//......
  • 多线程面试笔记
    1-多线程与并发基础1.1-线程和进程的区别什么是线程和进程?进程:程序由指令和数据组成,但这些指令要运行,数据要读写,就必须将指令加载至CPU,数据加载至内存。在指令运行过程中还需要用到磁盘、网络等设备。进程就是用来加载指令、管理内存、管理IO的。当一个程序被运行,......
  • AMD 线程撕裂者7970X 搭配双卡A5000,打造模具设计公司工作站虚拟化方案
    客户背景客户为一家模具设计公司,使用UG/NX设计软件,现有10名设计师。当前面临以下问题:信息安全:设计图纸存在泄密风险,无法确保数据安全。远程访问:设计师无法通过远程方式访问工作站进行设计工作。资源共享:设计工作站目前归属于个人,设计资源难以高效共享,工作站资源利用率较低......
  • 实验1 C++
    任务1:task.cpp:1#include<iostream>2#include<string>3#include<vector>4#include<algorithm>56usingnamespacestd;78//声明9//模板函数声明10template<typenameT>11voidoutput(constT&c);1213//......
  • 线程池监控2-监控线程池状态、线程数量和队列任务数量等
    1.实现原理这篇博文是基于线程池监控1-监控任务执行时间,原理是:创建一个固定时间间隔执行的线程,来记录线程池的池状态、线程数量和队列任务数量等,具体方案:使用单例类缓存所有创建的线程池对象,类创建时启动定时任务线程,定期遍历缓存中线程池,记录线程池信息。2.实现代码packa......
  • 实验1 C++
    任务1:task1.cpp1//现代C++标准库、算法库体验2//本例用到以下内容:3//1.字符串string,动态数组容器类vector、迭代器4//2.算法库:反转元素次序、旋转元素5//3.函数模板、const引用作为形参67#include<iostream>8#include<string>9......
  • 通用线程池1
    1publicclassCommonThreadPool{2privatestaticfinalCommonThreadPoolpool=newCommonThreadPool();3privateThreadPoolExecutorexecutor;4privateCommonThreadPool(){5intcorePoolSize=4;6intmaximumPoolSize......
  • 【c&c++】glib介绍
    glib库是Linux平台下最常用的C语言函数库,它具有很好的可移植性和实用性。glib是Gtk+库和Gnome的基础。glib可以在多个平台下使用,比如Linux、Unix、Windows等。glib为许多标准的、常用的C语言结构提供了相应的替代物。 如果在程序中要使用到glib库中的函数,则应该包含glib.h头......