C++消息队列,多线程



前言

本文提供了一种C++消息队列的实现方式(包括一个线程类和一个消息队列类),通过一个简单示例说明如何生产消息和消费消息。

一、类图

在这里插入图片描述

消息队列类

#pragma once
#include <mutex>
#include <condition_variable>
#include <queue>

namespace wxw
{
    template <typename Msg>
    class WMessageQueue
    {
    private:
        std::mutex m_msg_mutex;
        std::condition_variable m_cond;
        std::queue<std::shared_ptr<Msg>> m_queue;
        bool m_is_running = true;

    public:
        std::shared_ptr<Msg> receiveMsg()
        {
            std::unique_lock<std::mutex> lg(m_msg_mutex);
            m_cond.wait(lg, [this]()
                        { return (!m_queue.empty() || !m_is_running); });

            if (m_queue.empty())
            {
                return nullptr;
            }
            auto msg = m_queue.front();
            m_queue.pop();
            return msg;
        }

        void sendMessage(std::shared_ptr<Msg> const &msg)
        {
            std::unique_lock<std::mutex> lg(m_msg_mutex);
            m_queue.emplace(msg);
            m_cond.notify_one();
        }

        void stop()
        {
            m_is_running = false;
            m_cond.notify_one();
        }
    };

}

调用std::condition_variablewait方法前需要获取锁,wait会释放锁,并阻塞当前线程,直到wait的第二个参数返回true(某种条件满足),wait会重新上锁并执行下面的代码。
线程类

#pragma once
#include <thread>
#include "wang_message_queue.h"

namespace wxw
{
    template <typename Msg>
    class WThread
    {
    private:
        bool m_is_running;
        std::thread m_thread;
        WMessageQueue<Msg> m_message_queue;

        void run()
        {
            while (m_is_running)
            {
                auto msg = m_message_queue.receiveMsg();
                if (msg != nullptr)
                {
                    onMessage(msg);
                }
            }
        }

        void setThreadName(std::string const name)
        {
            pthread_setname_np(m_thread.native_handle(), name.c_str());
        }

    public:
        WThread() : m_is_running(true)
        {
            m_thread = std::thread(&WThread::run, this);
        }
        WThread(std::string const name) : m_is_running(true)
        {
            m_thread = std::thread(&WThread::run, this);
            setThreadName(name);
        }
        virtual ~WThread() = default;

        virtual void onMessage(std::shared_ptr<Msg> &msg) = 0;

        void sendMessage(std::shared_ptr<Msg> const &msg)
        {
            m_message_queue.sendMessage(msg);
        }

        void stop()
        {
            m_message_queue.stop();
            if (m_is_running)
            {
                m_is_running = false;
                m_thread.join();
            }
        }
    };
}

二、使用步骤

1.定义自己的消息体对象

消息体可以定义成抽象类,然后被各种消息类继承,本文只定义一个具体的消息类

//.h
#pragma once

namespace wxw
{
    class WorkMessage
    {
    private:
        /* data */
        int m_num;
        int m_id;
    public:
        WorkMessage(int num, int id);
        ~WorkMessage();

        void handleMessage();
    };
}

//.cpp
#include "work_message.h"
#include <iostream>
#include <unistd.h>

namespace wxw
{
    WorkMessage::WorkMessage(int num, int id)
        : m_num(num), m_id(gettid())
    {
    }
    WorkMessage::~WorkMessage()
    {
    }
    void WorkMessage::handleMessage()
    {
        std::cout << "num:" << m_num << ",id:" << m_id << std::endl;
    }
}

2.先定义自己的工作线程类

继承上述的类WThread

//.h
#pragma once
#include "wang_thread.h"
#include "work_message.h"

namespace wxw
{
    class WorkThread final : public WThread<WorkMessage>
    {
    private:
        /* data */
        WorkThread(std::string const thread_name = "work_thread");

    public:
        ~WorkThread() = default;

        static WorkThread &getInstance()
        {
            static WorkThread work_thread_instance;
            return work_thread_instance;
        }

        void onMessage(std::shared_ptr<WorkMessage> &msg) final;
    };
}

//.cpp
#include "work_thread.h"

namespace wxw
{

    WorkThread::WorkThread(std::string const thread_name)
        : WThread(thread_name)
    {
    }

    void WorkThread::onMessage(std::shared_ptr<WorkMessage> &msg)
    {
        msg->handleMessage();
    }
}

3.测试结果

3.1 单线程访问

#include "work_thread.h"
#include <unistd.h>

int main(int argc, char *argv[])
{
    int num = 0;
    while (true)
    {
        std::this_thread::sleep_for(std::chrono::milliseconds(1000));
        num++;
        wxw::WorkThread::getInstance().sendMessage(std::make_shared<wxw::WorkMessage>(num, gettid()));

        if (num == 10)
            break;
    }

    wxw::WorkThread::getInstance().stop();

    return 0;
}

测试结果
在这里插入图片描述

3.2 多线程访问

#include "work_thread.h"
#include <unistd.h>
#include <iostream>

void work_func()
{
    int num = 0;
    while (true)
    {
        // std::this_thread::sleep_for(std::chrono::milliseconds(1000));
        num++;
        wxw::WorkThread::getInstance().sendMessage(std::make_shared<wxw::WorkMessage>(num, gettid()));

        if (num == 10)
            break;
    }
    std::cout << "work func exit, id:" << gettid() << std::endl;
}

int main(int argc, char *argv[])
{
    std::thread t1(work_func);
    std::thread t2(work_func);

    t1.join();
    t2.join();

    wxw::WorkThread::getInstance().stop();

    return 0;
}

测试结果
在这里插入图片描述

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值