C++實(shí)現(xiàn)一個(gè)簡(jiǎn)單消息隊(duì)列的示例詳解
前言
消息隊(duì)列在多線程的場(chǎng)景有時(shí)會(huì)用到,尤其是線程通信跨線程調(diào)用的時(shí)候,就可以使用消息隊(duì)列進(jìn)行通信。C++實(shí)現(xiàn)一個(gè)能用的消息隊(duì)列還是比較簡(jiǎn)單的,只需要一個(gè)隊(duì)列一個(gè)互斥變量和一個(gè)條件變量,這些在標(biāo)準(zhǔn)庫(kù)中都有提供。基于曾經(jīng)寫(xiě)過(guò)的項(xiàng)目,總結(jié)出來(lái)最簡(jiǎn)單的消息隊(duì)列的實(shí)現(xiàn)將在下文中介紹。
一、如何實(shí)現(xiàn)
1、接口定義
一個(gè)基本的消息隊(duì)列只需要3個(gè)接口:
(1)推送消息
推送消息即是將消息寫(xiě)入隊(duì)列,這個(gè)通常采用異步實(shí)現(xiàn),推送之后立刻返回。如果要實(shí)現(xiàn)Windows的SendMessage則會(huì)比較復(fù)雜,最好的方式是放到外部實(shí)現(xiàn),消息隊(duì)列只提供異步推送消息。
void push(const T& msg);
(2)等待消息
等待隊(duì)列的消息,這個(gè)方法是同步的,只有接收到消息才會(huì)返回。
//等待消息 void wait(T& msg);
(3)輪詢消息
輪詢消息和等待消息一樣也是接收消息,只是無(wú)論是否接收到消息輪詢消息會(huì)立刻返回。輪詢消息也是有一定的使用場(chǎng)景,尤其是接收消息線程需要一定的調(diào)度邏輯時(shí)就需要輪詢消息避免線程堵塞。
bool poll(T& msg);
2、用到的對(duì)象
(1)隊(duì)列
我們使用一個(gè)隊(duì)列來(lái)存放消息
#include<queue> std::queue<T> _queue;
(2)互斥變量
使用一個(gè)互斥變量確保隊(duì)列的讀寫(xiě)線程安全
#include<mutex> std::mutex _mtx;
(3)條件變量
采用條件變量結(jié)合互斥變量實(shí)現(xiàn)消息的等待和通知。
#include<condition_variable> std::condition_variable _cv;
3、基本流程
線程通信

二、完整代碼
采用泛型實(shí)現(xiàn),消息類(lèi)型可以自定義。
#include<mutex>
#include<condition_variable>
#include<queue>
/// <summary>
/// 消息隊(duì)列
/// </summary>
/// <typeparam name="T">消息類(lèi)型</typeparam>
template<class T> class MessageQueue {
public:
/// <summary>
/// 推入消息
/// </summary>
/// <param name="msg">消息對(duì)象</param>
void push(const T& msg) {
std::unique_lock<std::mutex>lck(_mtx);
_queue.push(msg);
_cv.notify_one();
}
/// <summary>
/// 輪詢消息
/// </summary>
/// <param name="msg">消息對(duì)象</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">消息對(duì)象</param>
void wait(T& msg) {
std::unique_lock<std::mutex>lck(_mtx);
while (!_queue.size()) _cv.wait(lck);
msg = _queue.front();
_queue.pop();
}
//隊(duì)列長(zhǎng)度
size_t size() {
std::unique_lock<std::mutex>lck(_mtx);
return _queue.size();
}
private:
//隊(duì)列
std::queue<T> _queue;
//互斥變量
std::mutex _mtx;
//條件變量
std::condition_variable _cv;
};三、使用示例
線程通信
等待消息
#include<thread>
//自定義消息對(duì)象
class MyMessage {
public:
int type;
void* param1;
void* param2;
};
int main(int argc, char* argv[])
{
//初始化消息隊(duì)列
MessageQueue<MyMessage> mq;
//啟動(dòng)線程
std::thread t1([&]() {
MyMessage msg;
while (1) {
//等待隊(duì)列的消息
mq.wait(msg);
printf("receive message type:%d\n", msg.type);
if (msg.type == 1001)
break;
}
printf("thread exited\n");
});
//發(fā)送消息給線程
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>
//自定義消息對(duì)象
class MyMessage {
public:
int type;
void* param1;
void* param2;
};
int main(int argc, char* argv[])
{
//初始化消息隊(duì)列
MessageQueue<MyMessage> mq;
//啟動(dòng)線程
std::thread t1([&]() {
MyMessage msg;
while (1) {
//輪詢隊(duì)列的消息
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");
});
//發(fā)送消息給線程
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;
}
總結(jié)
以上就是今天要講的內(nèi)容,實(shí)現(xiàn)一個(gè)簡(jiǎn)單消息隊(duì)列還是比較容易的,尤其是c++有標(biāo)準(zhǔn)庫(kù)支持的情況下,也能滿足大部分使用場(chǎng)景,比如實(shí)現(xiàn)線程切換或者async、await底層就需要用到消息隊(duì)列。寫(xiě)這篇博文的主要目的也是用于記錄,以后需要用到的時(shí)候可直接網(wǎng)上拷貝。
到此這篇關(guān)于C++實(shí)現(xiàn)一個(gè)簡(jiǎn)單消息隊(duì)列的示例詳解的文章就介紹到這了,更多相關(guān)C++消息隊(duì)列內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
visual?studio?將編譯后的dll等文件自動(dòng)復(fù)制到指定目錄的方法
這篇文章主要介紹了visual?studio?將編譯后的dll等文件自動(dòng)復(fù)制到指定目錄,本文給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧2024-03-03
QT實(shí)戰(zhàn)之實(shí)現(xiàn)圖片瀏覽系統(tǒng)
這篇文章主要介紹了如何利用QT編寫(xiě)一個(gè)圖片瀏覽系統(tǒng),可以支持自動(dòng)播放,左右拖動(dòng)切換,點(diǎn)擊列表切換,點(diǎn)擊按鈕切換等功能,感興趣的小伙伴可以跟隨小編一起了解一下2023-04-04
C++實(shí)現(xiàn)LeetCode(60.序列排序)
這篇文章主要介紹了C++實(shí)現(xiàn)LeetCode(60.序列排序),本篇文章通過(guò)簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-07-07
C++基于EasyX圖形庫(kù)實(shí)現(xiàn)2048小游戲
這篇文章主要為大家詳細(xì)介紹了C++基于EasyX圖形庫(kù)實(shí)現(xiàn)2048小游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-02-02
c語(yǔ)言中十六進(jìn)制轉(zhuǎn)二進(jìn)制顯示的實(shí)現(xiàn)方法
本篇文章對(duì)c語(yǔ)言中十六進(jìn)制轉(zhuǎn)二進(jìn)制顯示的實(shí)現(xiàn)方法進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-05-05
C++ Boost Chrono實(shí)現(xiàn)計(jì)時(shí)碼表流程詳解
Boost是為C++語(yǔ)言標(biāo)準(zhǔn)庫(kù)提供擴(kuò)展的一些C++程序庫(kù)的總稱(chēng)。Boost庫(kù)是一個(gè)可移植、提供源代碼的C++庫(kù),作為標(biāo)準(zhǔn)庫(kù)的后備,是C++標(biāo)準(zhǔn)化進(jìn)程的開(kāi)發(fā)引擎之一,是為C++語(yǔ)言標(biāo)準(zhǔn)庫(kù)提供擴(kuò)展的一些C++程序庫(kù)的總稱(chēng)2022-11-11

