網站首頁 編程語言 正文
前言
消息隊列在多線程的場景有時會用到,尤其是線程通信跨線程調用的時候,就可以使用消息隊列進行通信。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底層就需要用到消息隊列。寫這篇博文的主要目的也是用于記錄,以后需要用到的時候可直接網上拷貝。
原文鏈接:https://blog.csdn.net/u013113678/article/details/127585569
相關推薦
- 2022-07-02 SpringBoot-?@SessionAttributes--使用/實例
- 2021-12-11 C語言SetConsoleCursorPosition函數使用方法_C 語言
- 2022-12-09 Opencv中的cv2.calcHist()函數的作用及返回值說明_python
- 2022-11-02 react父組件更改props子組件無法刷新原因及解決方法_React
- 2022-09-14 Android多渠道打包神器ProductFlavor詳解_Android
- 2023-01-15 GoLang?RabbitMQ?TTL與死信隊列以及延遲隊列詳細講解_Golang
- 2022-10-13 解析React中useMemo與useCallback的區別_React
- 2022-09-25 Spring核心IOC的核心類解析
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支