【Linux C/C++開發】Linux系統輕量級的隊列緩存mqueue

前言

? ? ? ? 開發設計時,通常會對業務流程進行模塊化,有些流程之間,不要求同步,但又需要傳遞信息時,如果存儲到數據庫,效率降低很多,如果是存放在內存是最好的。此時可以選擇系統的IPC(進程間通信,如共享內存等),本文講解的是適合輕量級的隊列緩存場景的mqueue。

功能講解

mqueue特性

????????Linux的mqueue(消息隊列)是POSIX標準中定義的進程間通信(IPC)機制,允許不同進程通過內核維護的隊列傳遞結構化消息。其具備以下幾個特性:

  • 存儲在指定文件:mqueue消息隊列文件默認掛載在/dev/mqueue目錄下。通過mq_open創建的消息隊列會在此目錄生成對應文件節點,內核使用紅黑樹管理消息的存儲與優先級
  • 持久性:POSIX消息隊列隨系統重啟消失
  • 可在命令行查看隊列信息:cat /dev/mqueue/[隊列名] ?# 查看隊列屬性(如最大消息數、消息大小)

功能介紹

需求場景:某些功能需要在root用戶下作為服務執行,組裝的生產數據需要推送給登錄系統桌面的普通用戶權限的應用。

下面以在root權限下運行的讀取usb信息的服務,監測USB的插拔事件并把信息推送到mqueue,而普通用戶的應用通過讀取mqueue獲取USB插拔信息為例。

獲取事件信息寫入mqueue

#ifndef USBACTION_H_
#define USBACTION_H_
#include <unistd.h>
#include <cstring>
#include <iostream>
#include <sstream>
#include <string>
#include <algorithm>
#include <vector>#include <cstdio>
#include <stdio.h>
#include <dlfcn.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <libudev.h>
#include <mqueue.h>
using namespace std;
#define MAX_NUM 100struct Message {long mtype; // 消息類型char mtext[256]; // 消息內容
};const int MSG_TYPE = 1;
const char* QUEUE_NAME = "/usb_msg";//在/dev/mqueue目錄下class Usbaction: public TUtilBase {
public:Usbaction();~Usbaction();int Run();private://int Init();//初始化void monitorDevices();int sendtomqueue(const char* mqstr);unsigned int uSleepTime;                //刷新間隔};#endif /* USBACTION_H_ */
#include "usbaction.h"std::vector<std::string> split(const std::string& str, char delimiter) {std::vector<std::string> tokens;std::istringstream tokenStream(str);std::string token;while (std::getline(tokenStream, token, delimiter)) {tokens.push_back(token);}return tokens;
}Usbaction::Usbaction() {uSleepTime = 5;
}Usbaction::~Usbaction() {
}int Usbaction::sendtomqueue(const char* mqstr){mqd_t mq;struct mq_attr attr;attr.mq_flags = O_NONBLOCK;  // 設置為非阻塞模式attr.mq_maxmsg = MAX_NUM;	 // 隊列中最大消息數attr.mq_msgsize = sizeof(Message);// 消息的最大大小(字節)attr.mq_curmsgs = 0;         // 隊列中當前消息數mq = mq_open(QUEUE_NAME, O_CREAT | O_WRONLY, 0644, &attr);if (mq == (mqd_t)-1) {WRITELOG(LOG_ERROR,"mq_open Error");return 0;}Message msg;msg.mtype = MSG_TYPE;strcpy(msg.mtext,mqstr);//attr.mq_flags |= O_NONBLOCK;if (mq_setattr(mq, &attr, NULL) == -1) {return 0;}if (mq_send(mq, reinterpret_cast<char*>(&msg), sizeof(msg), 0) == -1) {if (errno == EAGAIN) {} else {perror("mq_send");}}else {std::cout << "Message sent: " << msg.mtext << std::endl;}// 關閉消息隊列mq_close(mq);return 1;
}void Usbaction::monitorDevices() {// 創建 udev 對象struct udev *udev = udev_new();if (!udev) {return;}// 創建 udev 監視器struct udev_monitor *mon = udev_monitor_new_from_netlink(udev, "udev");if (!mon) {udev_unref(udev);return;}// 添加過濾器以匹配usb 子系統udev_monitor_filter_add_match_subsystem_devtype(mon, "usb", nullptr);udev_monitor_enable_receiving(mon);std::cout << "Monitoring block and USB events. Press Ctrl+C to exit." << std::endl;while (true) {struct udev_device *dev = udev_monitor_receive_device(mon);if (dev) {bool bfind=false;std::string level="";const char* subsystem = udev_device_get_subsystem(dev);const char* action = udev_device_get_action(dev);const char* devnode = udev_device_get_devnode(dev);const char *pro = udev_device_get_property_value(dev, "ID_USB_INTERFACES");if (subsystem && action && devnode) {if (strcmp(action,"add")==0||strcmp(action,"remove")==0){bfind=true;std::vector<std::string> tokens = split(devnode, '/');// 確保有至少兩個分割結果if (tokens.size() >= 2) {string device = tokens[tokens.size() - 1];string bus = tokens[tokens.size() - 2];level = bus + ":" + device;}}}if (bfind) {const char* idVendor = udev_device_get_sysattr_value(dev,"idVendor");const char* idProduct = udev_device_get_sysattr_value(dev, "idProduct");if (idVendor && idProduct) {//strcmp(action,"add")==0char sendbuf[256]={0};if(pro){sprintf(sendbuf,"%s,%s,%s:%s,%s",action,level.c_str(),idVendor,idProduct,pro);}elsesprintf(sendbuf,"%s,%s,%s:%s",action,level.c_str(),idVendor,idProduct);sendtomqueue(sendbuf);
%s",action,level.c_str(),idVendor,idProduct);}else{char sendbuf[256]={0};sprintf(sendbuf,"%s,%s",action,level.c_str());sendtomqueue(sendbuf);}}udev_device_unref(dev);}usleep(500000); // Sleep for 0.5 seconds}udev_monitor_unref(mon);udev_unref(udev);
}int Usbaction::Init() {//logif (0== BInit(APP_TYPE_LOG, ACTIVITYCENSUS_LOG, 0)) {return 0;}return 1;
}int Usbaction::Run() {//初始化if (NS_FAILED == Init()) {return 0;}monitorDevices();return 1;
}int main(int argc, char **argv) {Usbaction action;action.Run();return 0;}

makefile

CC        = g++
CFLAGS    =
DEBUGFLAG = -g -Wall
MACRO     =
#MACRO     = -D_DEBUG 
LIBDIRS   = 
LIBS      = -ldl -ludev -lrt
INCLUDE   = 
MAKE_SO   = 
OPTIONS   = 
OBJDIR    =
SRCDIR    =
RUNOUTPUT = usbaction
LIBOUTPUT =
OBJS      = usbaction.odefault:$(RUNOUTPUT)clean:rm -f $(OBJS) $(RUNOUTPUT)install:cp -f $(RUNOUTPUT) ../../bin$(RUNOUTPUT):$(OBJS)$(CC)   -o $(RUNOUTPUT) $^ $(OPTIONS)  $(LIBDIRS) $(LIBS).cpp.o:$(CC) $(DEBUGFLAG) $(MACRO) -fPIC -c $< -o $@ $(CFLAGS) $(INCLUDE)

讀取mqueue

普通應用權限的應用可以讀取root用戶權限的mqueue文件,下面是非阻塞式讀取隊列數據。

#include <iostream>
#include <mqueue.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <cstring>
#include <unistd.h>struct Message {long mtype;        // 消息類型char mtext[256];   // 消息內容
};const char* QUEUE_NAME = "/ymore_msg"; // 消息隊列的名稱int main() {// 打開消息隊列以讀取模式mqd_t mq = mq_open(QUEUE_NAME, O_RDONLY | O_NONBLOCK);if (mq == (mqd_t)-1) {std::cerr << "Error opening message queue: " << strerror(errno) << std::endl;return 1;}Message msg;ssize_t bytes_read;// 循環接收消息while (true) {bytes_read = mq_receive(mq, reinterpret_cast<char*>(&msg), sizeof(msg), NULL);if (bytes_read == -1) {std::cerr << "Error receiving message: " << strerror(errno) << std::endl;break;}std::cout << "Received message: " << msg.mtext << std::endl;// 如果讀取到隊列為空,可以根據條件退出// 例如,使用 `mq_getattr()` 獲取隊列的當前狀態struct mq_attr attr;if (mq_getattr(mq, &attr) == -1) {std::cerr << "Error getting queue attributes: " << strerror(errno) << std::endl;break;}// 如果隊列中沒有消息,退出循環if (attr.mq_curmsgs == 0) {std::cout << "No more messages in the queue." << std::endl;break;}}// 關閉消息隊列mq_close(mq);return 0;
}

結尾

? ? ? ? Linux后臺C/C++項目,一般在架構設計時,可以設計共享內容來內部處理緩存數據,但也有考慮到第三方應用或者擴展型應用的場景,此時mqueue是比較合適了,如果是高并發的隊列緩存,還是得找成熟的隊列緩存中間件,比如kafka。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/895942.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/895942.shtml
英文地址,請注明出處:http://en.pswp.cn/news/895942.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Vue 實現通過URL瀏覽器本地下載 PDF 和 圖片

1、代碼實現如下&#xff1a; 根據自己場景判斷 PDF 和 圖片&#xff0c;下載功能可按下面代碼邏輯執行 const downloadFile async (item: any) > {try {let blobUrl: any;// PDF本地下載if (item.format pdf) {const response await fetch(item.url); // URL傳遞進入i…

計算機網絡基礎雜談(局域網、ip、子網掩碼、網關、DNS)

目錄 1. 簡單局域網的構成 2. IP 地址 3. 子網掩碼 4. IP地址詳解自定義IP 5. IP 地址詳解 6. 網關 7. DNS 域名解析 8. ping 1. 簡單局域網的構成 交換機是組建局域網最重要的設備&#xff0c;換句話說&#xff0c;沒有交換機就沒法搭建局域網 交換機不能讓局域網連…

Thor: 統一AI模型網關的革新之選

項目價值 Thor(雷神托爾)作為一個強大的AI模型管理網關&#xff0c;解決了當前AI領域一個關鍵痛點&#xff1a;不同AI服務商的API格式各異&#xff0c;集成成本高。Thor通過將各種AI模型的獨特格式統一轉換為OpenAI格式&#xff0c;顯著降低了開發者的使用門檻和維護成本。 核…

25年2月通信基礎知識補充:多普勒頻移與多普勒擴展、3GPP TDL信道模型

看文獻過程中不斷發現有太多不懂的基礎知識&#xff0c;故長期更新這類blog不斷補充在這過程中學到的知識。由于這些內容與我的研究方向并不一定強相關&#xff0c;故記錄不會很深入請見諒。 【通信基礎知識補充7】25年2月通信基礎知識補充1 一、多普勒頻移與多普勒擴展傻傻分不…

【Python】Python入門——筆記合集

哈哈 00、環境搭建 學習Python&#xff0c;首先需要搭建一個本地開發環境&#xff0c;或是使用線上開發環境&#xff08;各類練習網站&#xff09;&#xff0c;這篇博客里主要記錄了本地開發環境的配置方法。內容包括python解釋器的安裝以及pycharm的安裝、漢化等。 博客地…

為什么mvcc中?m_ids 列表并不等同于 min_trx_id 和 max_trx_id 之間的所有事務 ID

首先我們要明確 m_ids 表示創建 ReadView 時&#xff0c;系統中所有活躍&#xff08;未提交&#xff09;事務的事務 ID 列表。 僅包含當前未提交的事務&#xff0c;與事務 ID 的數值范圍無關。 min_trx_id 是 m_ids 中的最小值。若 m_ids 為空&#xff0c;則 min_trx_id 等于…

使用 Spark NLP 實現中文實體抽取與關系提取

在自然語言處理(NLP)領域,實體抽取和關系提取是兩個重要的任務。實體抽取用于從文本中識別出具有特定意義的實體(如人名、地名、組織名等),而關系提取則用于識別實體之間的關系。本文將通過一個基于 Apache Spark 和 Spark NLP 的示例,展示如何實現中文文本的實體抽取和…

FPGA開發要學些什么?如何快速入門?

隨著FPGA行業的不斷發展&#xff0c;政策的加持和投入的研發&#xff0c;近兩年FPGA行業的薪資也是水漲船高&#xff0c;一些人轉行后拿到了薪資30W&#xff0c;甚至有一些能力強的人可以拿到60W&#xff0c;看到這里想必不少人表示很心動&#xff0c;但又不知道怎么轉&#xf…

使用Python和正則表達式爬取網頁中的URL數據

在數據抓取和網絡爬蟲開發中&#xff0c;提取網頁中的URL是一個常見的需求。無論是用于構建網站地圖、分析鏈接結構&#xff0c;還是進行內容聚合&#xff0c;能夠高效地從HTML文檔中提取URL都是一個重要的技能。Python作為一種強大的編程語言&#xff0c;結合其正則表達式模塊…

人工智能之目標追蹤DeepSort源碼解讀(yolov5目標檢測,代價矩陣,余弦相似度,馬氏距離,匹配與預測更新)

要想做好目標追蹤,須做好目標檢測,所以這里就是基于yolov5檢測基礎上進行DeepSort,叫它為Yolov5_DeepSort。整體思路是先檢測再追蹤,基于檢測結果進行預測與匹配。 一.參數與演示 這里用到的是coco預訓練人的數據集&#xff1a; 二.針對檢測結果初始化track 對每一幀數據都輸出…

C++藍橋杯基礎篇(四)

片頭 嗨~小伙伴們&#xff0c;大家好&#xff01;今天我們來學習C藍橋杯基礎篇&#xff08;四&#xff09;&#xff0c;繼續練習相關習題。準備好了嗎&#xff1f;咱們開始咯~ 題目1 連續整數相加 思路分析&#xff1a; 這道題&#xff0c;我們可以把從鍵盤中讀取n寫在while循…

YOLOv12從入門到入土(含結構圖)

論文鏈接&#xff1a;https://arxiv.org/abs/2502.12524 代碼鏈接&#xff1a;https://github.com/sunsmarterjie/yolov12 文章摘要&#xff1a; 長期以來&#xff0c;增強YOLO框架的網絡架構一直至關重要&#xff0c;但一直專注于基于cnn的改進&#xff0c;盡管注意力機制在建…

SpringSecurity基于配置方法控制訪問權限:MVC匹配器、Ant匹配器

Spring Security 是一個功能強大且高度可定制的身份驗證和訪問控制框架。在 Spring Security 中&#xff0c;可以通過配置方法來控制訪問權限。認證是實現授權的前提和基礎&#xff0c;在執行授權操作前需要明確目標用戶&#xff0c;只有明確目標用戶才能明確它所具備的角色和權…

【iOS】SwiftUI狀態管理

State ObservedObject StateObject 的使用 import SwiftUIclass CountModel: ObservableObject {Published var count: Int 0 // 通過 Published 標記的變量會觸發視圖更新init() {print("TimerModel initialized at \(count)")} }struct ContentView: View {State…

跟著 Lua 5.1 官方參考文檔學習 Lua (3)

文章目錄 2.5 – Expressions2.5.1 – Arithmetic Operators2.5.2 – Relational Operators2.5.3 – Logical Operators2.5.4 – Concatenation2.5.5 – The Length Operator2.5.6 – Precedence2.5.7 – Table Constructors2.5.8 – Function Calls2.5.9 – Function Definiti…

(LLaMa Factory)大模型訓練方法--監督微調(Qwen2-0.5B)

1、準備訓練數據&#xff1a;SFT 的數據格式有多種&#xff0c;例如&#xff1a;Alpaca格式、OpenAI格式等。 #其中Alpaca格式如下&#xff1a;[{"instruction":"human instruction (required)","input":"human input (optional)",&qu…

Sojson高級加密技術科普

1. 引言 什么是Sojson&#xff1f; Sojson是一款用于JavaScript代碼加密與混淆的工具&#xff0c;它能夠有效保護前端代碼的知識產權&#xff0c;避免開發者的心血被隨意竊取。 為什么需要代碼加密&#xff1f; 在當今的互聯網環境下&#xff0c;代碼被輕易復制、篡改或逆向…

自制簡單的圖片查看器(python)

圖片格式&#xff1a;支持常見的圖片格式&#xff08;JPG、PNG、BMP、GIF&#xff09;。 import os import tkinter as tk from tkinter import filedialog, messagebox from PIL import Image, ImageTkclass ImageViewer:def __init__(self, root):self.root rootself.root.…

【核心算法篇十三】《DeepSeek自監督學習:圖像補全預訓練方案》

引言:為什么自監督學習成為AI新寵? 在傳統監督學習需要海量標注數據的困境下,自監督學習(Self-Supervised Learning)憑借無需人工標注的特性異軍突起。想象一下,如果AI能像人類一樣通過觀察世界自我學習——這正是DeepSeek圖像補全方案的技術哲學。根據,自監督學習通過…

Nginx下proxy_redirect的三種配置方式

Nginx中的proxy_redirect指令&#xff0c;用于修改代理服務器接收到的后端服務器響應中的重定向URL。在代理環境中&#xff0c;若后端返回的重定向URL不符合客戶端需求&#xff0c;就用它調整。 語法 proxy_redirect default; proxy_redirect redirect replacement; proxy_…