C++实现一个简单消息队列的示例详解

 更新时间:2022年12月15日 11:02:57   作者:CodeOfCC  
消息队列在多线程的场景有时会用到,尤其是线程通信跨线程调用的时候,就可以使用消息队列进行通信。本文将利用C++实现一个简单的消息队列,感兴趣的可以了解一下

前言

消息队列在多线程的场景有时会用到,尤其是线程通信跨线程调用的时候,就可以使用消息队列进行通信。C++实现一个能用的消息队列还是比较简单的,只需要一个队列一个互斥变量和一个条件变量,这些在标准库中都有提供。基于曾经写过的项目,总结出来最简单的消息队列的实现将在下文中介绍。

一、如何实现

1、接口定义

一个基本的消息队列只需要3个接口:

(1)推送消息

推送消息即是将消息写入队列,这个通常采用异步实现,推送之后立刻返回。如果要实现Windows的SendMessage则会比较复杂,最好的方式是放到外部实现,消息队列只提供异步推送消息。

void push(const T& msg);    

(2)等待消息

等待队列的消息,这个方法是同步的,只有接收到消息才会返回。

//等待消息
void wait(T& msg);

(3)轮询消息

轮询消息和等待消息一样也是接收消息,只是无论是否接收到消息轮询消息会立刻返回。轮询消息也是有一定的使用场景,尤其是接收消息线程需要一定的调度逻辑时就需要轮询消息避免线程堵塞。

bool poll(T& msg);

2、用到的对象

(1)队列

我们使用一个队列来存放消息

#include<queue>
std::queue<T> _queue;

(2)互斥变量

使用一个互斥变量确保队列的读写线程安全

#include<mutex>
std::mutex _mtx;

(3)条件变量

采用条件变量结合互斥变量实现消息的等待和通知。

#include<condition_variable>
std::condition_variable _cv;

3、基本流程

线程通信

二、完整代码

采用泛型实现,消息类型可以自定义。

#include<mutex>
#include<condition_variable>
#include<queue>
/// <summary>
/// 消息队列
/// </summary>
/// <typeparam name="T">消息类型</typeparam>
template<class T> class MessageQueue {
public:
    /// <summary>
    /// 推入消息
    /// </summary>
    /// <param name="msg">消息对象</param>
    void push(const T& msg) {
        std::unique_lock<std::mutex>lck(_mtx);
        _queue.push(msg);
        _cv.notify_one();
    }
    /// <summary>
    /// 轮询消息
    /// </summary>
    /// <param name="msg">消息对象</param>
    /// <returns>是否接收到消息</returns>
    bool poll(T& msg) {
        std::unique_lock<std::mutex>lck(_mtx);
        if (_queue.size())
        {
            msg = _queue.front();
            _queue.pop();
            return true;
        }
        return false;
    }
    /// <summary>
    /// 等待消息
    /// </summary>
    /// <param name="msg">消息对象</param>
    void wait(T& msg) {
        std::unique_lock<std::mutex>lck(_mtx);
        while (!_queue.size()) _cv.wait(lck);
        msg = _queue.front();
        _queue.pop();
    }
    //队列长度
    size_t size() {
        std::unique_lock<std::mutex>lck(_mtx);
        return _queue.size();
    }
private:
    //队列
    std::queue<T> _queue;
    //互斥变量
    std::mutex _mtx;
    //条件变量
    std::condition_variable _cv;
};

三、使用示例

线程通信

等待消息

#include<thread>
//自定义消息对象
class MyMessage {
public:
    int type;
    void* param1;
    void* param2;
};
int main(int argc, char* argv[])
{
    //初始化消息队列
    MessageQueue<MyMessage> mq;
    //启动线程
    std::thread t1([&]() {
        MyMessage msg;
        while (1) {
            //等待队列的消息
            mq.wait(msg);
            printf("receive message type:%d\n", msg.type);
            if (msg.type == 1001)
                break;
        }
        printf("thread exited\n");
        });
    //发送消息给线程
    MyMessage msg;
    printf("send number message to thread.1001 exit\n");
    while (1)
    {
        scanf("%d", &msg.type);
        mq.push(msg);
        if (msg.type == 1001)
            break;
    }
    t1.join();
    return 0;
}

轮询消息

#include<thread>
//自定义消息对象
class MyMessage {
public:
    int type;
    void* param1;
    void* param2;
};
int main(int argc, char* argv[])
{
    //初始化消息队列
    MessageQueue<MyMessage> mq;
    //启动线程
    std::thread t1([&]() {
        MyMessage msg;
        while (1) {
            //轮询队列的消息
            if (mq.poll(msg))
            {
                printf("receive message type:%d\n", msg.type);
                if (msg.type == 1001)
                    break;
            }
            std::this_thread::sleep_for(std::chrono::milliseconds(10));
        }
        printf("thread exited\n");
        });
    //发送消息给线程
    MyMessage msg;
    printf("send number message to thread.1001 exit\n");
    while (1)
    {
        scanf("%d", &msg.type);
        mq.push(msg);
        if (msg.type == 1001)
            break;
    }
    t1.join();
    return 0;
}

总结

以上就是今天要讲的内容,实现一个简单消息队列还是比较容易的,尤其是c++有标准库支持的情况下,也能满足大部分使用场景,比如实现线程切换或者async、await底层就需要用到消息队列。写这篇博文的主要目的也是用于记录,以后需要用到的时候可直接网上拷贝。

到此这篇关于C++实现一个简单消息队列的示例详解的文章就介绍到这了,更多相关C++消息队列内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • MFC对话框中实现走马灯效果

    MFC对话框中实现走马灯效果

    这篇文章主要为大家详细介绍了MFC对话框中实现走马灯效果,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-05-05
  • C语言二叉树的概念结构详解

    C语言二叉树的概念结构详解

    二叉树可以简单理解为对于一个节点来说,最多拥有一个上级节点,同时最多具备左右两个下级节点的数据结构。本文将详细介绍一下C++中二叉树的实现和遍历,需要的可以参考一下
    2022-08-08
  • C语言实现的程序员老黄历实例

    C语言实现的程序员老黄历实例

    这篇文章主要介绍了C语言实现的程序员老黄历,涉及日期的判定及流程控制的相关技巧,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-07-07
  • C++利用inotify+epoll实现异步文件监控的方法

    C++利用inotify+epoll实现异步文件监控的方法

    这篇文章讲给大家详细介绍一下C++利用inotify+epoll实现异步文件监控的方法,inotify是一种异步文件监控机制,文章通过代码示例介绍的非常详细,具有一定的参考价值,需要的朋友可以参考下
    2023-08-08
  • 线程崩溃不会导致 JVM 崩溃的原因解析

    线程崩溃不会导致 JVM 崩溃的原因解析

    网上看到一个很有意思的据说是美团的面试题:为什么线程崩溃崩溃不会导致 JVM 崩溃,这个问题我看了不少回答,但都没答到根本原因,所以决定答一答,相信大家看完肯定会有收获,本文分以下几节来探讨,需要的朋友可以参考下
    2022-06-06
  • C++实现LeetCode(107.二叉树层序遍历之二)

    C++实现LeetCode(107.二叉树层序遍历之二)

    这篇文章主要介绍了C++实现LeetCode(107.二叉树层序遍历之二),本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下
    2021-07-07
  • Objective-C中使用STL标准库Queue队列的方法详解

    Objective-C中使用STL标准库Queue队列的方法详解

    这篇文章主要介绍了Objective-C中使用STL标准库Queue队列的方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧
    2024-01-01
  • 浅谈C++性能榨汁机之伪共享

    浅谈C++性能榨汁机之伪共享

    使给定内存位置被一个线程所访问,可能还是会有乒乓缓存的存在,是因为另一种叫做伪共享(false sharing)的效应。即使数据存储在缓存行中,多个线程对数据中的成员进行访问时,硬件缓存还是会产生乒乓缓存。本文将介绍C++中的伪共享
    2021-06-06
  • C++中vector的清理回收的方式

    C++中vector的清理回收的方式

    这篇文章主要介绍了C++中vector的清理回收的方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-08-08
  • C++编程语言中赋值运算符重载函数(operator=)的使用

    C++编程语言中赋值运算符重载函数(operator=)的使用

    本文主要介绍了C++编程语言中赋值运算符重载函数(operator=)介绍,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-06-06

最新评论