使用C++11实现的非阻塞消息总线message_bus

0. 引言

消息总线(Message Bus)作为一种重要的通信模式,被应用于解耦系统中的组件,实现异步通信和事件驱动架构。
本文将介绍如何使用C++11实现一个非阻塞消息总线,通过异步处理消息来提高系统的并发性能和响应速度。

1. 设计方案

1.1 分析代码

头文件包含和类型定义

#pragma once

#include <map>
#include <vector>
#include <list>
#include <mutex>
#include "timer.hpp"

typedef std::function<void(std::string param1, int param2)> Callback_t;
typedef std::function<void()> TimeOutCallback_t;

enum CallbackType_t
{
    ALWAYS = 0,
    ONCE
};

struct CallbackItem_t
{
    Callback_t callback = nullptr;  
    TimeOutCallback_t timeOutCallback = nullptr;
    uint32_t timeoutInterval = 1000;    // milliseconds
    uint64_t timeoutStamp = 0;  // microseconds
    std::vector<int> msgNumVec;
    CallbackType_t callbackType = ALWAYS;
};
  • 类型定义: 定义了回调函数类型 Callback_t 和超时回调函数类型 TimeOutCallback_t,以及消息回调类型 CallbackItem_t,包含回调函数、超时回调、超时时间间隔、消息号列表和回调类型。

MessageBus 类定义

class MessageBus
{
public:
    static MessageBus& instance()
    {
        static MessageBus ins;
        return ins;
    }
    void publish(int msg, std::string param1, int param2 = 0);
    void timeOutCheck();
    bool subscribe(CallbackItem_t);
    void reset();
    void stop();
    void start();

private:
    MessageBus() = default;
    MessageBus(const MessageBus&) = delete;
    MessageBus& operator= (const MessageBus&) = delete;

    typedef std::shared_ptr<CallbackItem_t> CallbackItem_ptr;
    bool subscribe(int msg, CallbackItem_ptr);
    bool unsubscribe(int msg, CallbackItem_ptr);
    void regTimeOutCallback(CallbackItem_ptr);
    
    typedef std::map<int, std::vector<CallbackItem_ptr>> CallbackMap_t;
    CallbackMap_t _callbackMap;   // message dispatch map

    std::list<CallbackItem_ptr> _timeoutCheckList;    // timeout check list

    std::mutex _timeoutCheckListMutex;
    std::mutex _callbackMapMutex;
    Timer _timer;
};
  • 成员变量:

    • _callbackMap:消息号到回调函数列表的映射,用于存储订阅关系。
    • _timeoutCheckList:超时检查列表,存储需要检查超时的回调函数列表。
    • _timeoutCheckListMutex_callbackMapMutex:互斥量,用于保护 _timeoutCheckList_callbackMap 的并发访问。
    • _timer:定时器对象,用于定期执行超时检查。
  • 成员函数:

    • subscribeunsubscribe:订阅和取消订阅消息。
    • regTimeOutCallback:注册超时回调函数。
    • startstop:启动和停止消息总线的超时检查。
    • publish:发布消息,触发相应的回调函数,并处理超时逻辑。
    • timeOutCheck:超时检查函数,定期检查超时并执行超时回调函数。

辅助函数

static uint64_t getTimeStamp()
{
    std::chrono::microseconds ms = std::chrono::duration_cast<std::chrono::microseconds>(
        std::chrono::system_clock::now().time_since_epoch()
        );

    return ms.count();
}
  • getTimeStamp:获取当前时间戳(微秒级)的静态辅助函数。

方法实现

  • subscribeunsubscribe:通过 _callbackMap 管理消息的订阅关系。
  • regTimeOutCallback:计算超时时间戳并将回调函数加入 _timeoutCheckList
  • startstop:控制定时器的启动和停止。
  • publish:发布消息,根据消息号查找并执行相应的回调函数,同时处理超时逻辑。

1.2. 流程图

根据上述代码实现的功能,绘制如下流程图来说明消息总线的工作流程:

MessageBus
Subscribe
Unsubscribe
Publish
Timer
CallbackMap
CallbackMap
TimeoutCheckList
CheckTimeout
ExecuteTimeoutCallback

流程说明:

  1. MessageBus 是消息总线的核心控制器,负责处理订阅、取消订阅和发布消息等功能。
  2. SubscribeUnsubscribe 分别用于添加和移除消息的订阅关系。
  3. Publish 通过查找 CallbackMap 执行消息的回调函数,并处理超时逻辑。
  4. Timer 控制定时器的启动和停止,定期触发超时检查。
  5. CallbackMap 存储了消息号与对应的回调函数列表。
  6. TimeoutCheckList 存储了需要进行超时检查的回调函数列表。
  7. CheckTimeout 检查超时,如果超时则执行相应的超时回调函数。
  8. ExecuteTimeoutCallback 执行超时时的回调函数逻辑。

3. 优缺点分析

优点:

  • 高并发支持: 使用非阻塞队列和异步处理,能够有效支持高并发的消息处理需求,提高系统的吞吐量和响应速度。
  • 低延迟: 避免了传统同步阻塞方式下可能出现的长时间等待,通过异步处理消息可以大大降低消息处理的延迟。
  • 模块化设计: 使用模板和函数对象,支持灵活的消息类型和订阅行为,使得系统更易于扩展和维护。

缺点:

  • 资源消耗: 需要额外的工作线程来处理消息队列,可能增加系统的资源消耗,特别是在高并发和大量消息处理的情况下。
  • 复杂性增加: 需要处理线程安全性和消息处理的异步逻辑,可能增加代码的复杂度和维护成本,需要谨慎设计和测试。
### 回答1: #include <stdio.h> #include <string.h> #include <gst/gst.h> #include <gst/app/gstappsrc.h>//定义管道 static GstElement *pipeline;//定义推流地址 static gchar *uri = "rtsp://localhost:8554/stream";//定义错误处理 static void cb_message(GstBus *bus, GstMessage *msg, gpointer data){ g_print("MESSAGE:%s\n",GST_MESSAGE_TYPE_NAME(msg)); g_print("Got %s message\n", GST_MESSAGE_TYPE_NAME(msg)); switch (GST_MESSAGE_TYPE(msg)) { case GST_MESSAGE_ERROR: { GError *err; gchar *debug; gst_message_parse_error(msg, &err, &debug); g_print("Error: %s\n", err->message); g_error_free(err); g_free(debug); gst_element_set_state(pipeline, GST_STATE_READY); break; } default: break; } }int main(int argc, char *argv[]){ //初始化gstreamer gst_init(&argc, &argv); //创建元素 pipeline = gst_pipeline_new("pipeline"); //创建摄像头 GstElement *camera = gst_element_factory_make("nvarguscamerasrc","camera"); //创建视频转码器 GstElement *encoder = gst_element_factory_make("omxh264enc","encoder"); //创建视频封装器 GstElement *muxer = gst_element_factory_make("mp4mux","muxer"); //创建推流器 GstElement *rtppay = gst_element_factory_make("rtph264pay","rtppay"); //创建推流地址 GstElement *sink = gst_element_factory_make("udpsink","sink"); g_object_set(sink, "host", "127.0.0.1", "port", 8554, NULL); //添加到管道 gst_bin_add_many(GST_BIN(pipeline), camera, encoder, muxer, rtppay, sink, NULL); //连接 gst_element_link_many(camera, encoder, muxer, rtppay, sink, NULL); //获取管道的消息总线 GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(pipeline)); //安装消息回调函数 gst_bus_add_watch(bus, cb_message, NULL); gst_object_unref(bus); //设置推流地址 g_object_set(G_OBJECT(sink), "uri", uri, NULL); //运行管道 gst_element_set_state(pipeline, GST_STATE_PLAYING); //等待管道结束 gst_element_get_state(pipeline, NULL, NULL, -1); //释放资源 gst_element_set_state(pipeline, GST_STATE_NULL); gst_object_unref(GST_OBJECT(pipeline)); return 0; } ### 回答2: 以下是一个使用C语言实现的NVIDIA打开摄像头并推流RTSP的代码示例: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #define CAMERA_DEVICE "/dev/video0" #define RTSP_SERVER_URL "rtsp://your_rtsp_server_address" int main() { // 打开摄像头 char command[100]; sprintf(command, "nvgstcapture-1.0 --sensor-id 0 --capture-auto --file-name test.mp4"); system(command); // 推流RTSP sprintf(command, "nvgststream-1.0 --camsrc %s --protocol-name RTSP --client-ip your_ip_address --client-port 8554", CAMERA_DEVICE); system(command); return 0; } ``` 这段代码使用系统命令行工具`nvgstcapture-1.0`打开摄像头,并将视频流保存到`test.mp4`文件中。然后使用`nvgststream-1.0`将摄像头捕获到的视频流推流到指定的RTSP服务器地址。你需要将`your_rtsp_server_address`替换为实际的RTSP服务器地址,将`your_ip_address`替换为你的IP地址。 请注意,以上示例使用了NVIDIA的`nvgstcapture-1.0`和`nvgststream-1.0`命令行工具,需要事先在系统中安装并配置好相应的环境。另外,这只是一个简单的示例,实际场景中可能需要更多的参数配置和错误处理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

橘色的喵

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值