C++11线程、消息队列封装

ThreadObject.hpp

class ThreadObject
{
    using Func = std::function<void()>;
    const static int kInfinite = -1;

public:
    ThreadObject()
    {
        m_bStop.store(false);
    }

    ~ThreadObject()
    {
        Stop();
    }

    void Start(Func func, int nWaitMSeond = kInfinite)
    {
        do_work(func, nWaitMSeond);
    }

    void StartOnce(Func func)
    {
        Stop();
        m_bStop.store(false);
        m_thWork = std::thread([=] {
            if (func)
            {
                func();
            }
            });
    }

    void StartAndWait(Func func, int nWaitMSeond = kInfinite)
    {
        do_work(func, nWaitMSeond, true);
    }

    void Stop()
    {
        m_bStop.store(true);
        m_cvCond.notify_one();
        if (m_thWork.joinable())
            m_thWork.join();
    }

    void SetEvent()
    {
        m_cvCond.notify_one();
    }

    bool IsRunning()
    {
        return (!m_bStop.load());
    }


private:
    ThreadObject(const ThreadObject&) = delete;
    ThreadObject& operator=(const ThreadObject&) = delete;

    ThreadObject(const ThreadObject&&) = delete;
    ThreadObject& operator=(const ThreadObject&&) = delete;


private:
    void do_work(Func func, int nWaitMSeond, bool bWait = false)
    {
        Stop();
        m_bStop.store(false);
        m_bWork = !bWait;
        m_thWork = std::thread([=] {
            while (!this->m_bStop.load())
            {
                if (this->m_bWork.load() && func)
                {
                    func();
                }
                if (!this->m_bWork.load())
                {
                    this->m_bWork = true;
                }

                if (!this->m_bStop.load() )
                {
                    std::unique_lock<std::mutex> lock(m_mtLock);
                    if (kInfinite == nWaitMSeond)
                    {
                        m_cvCond.wait(lock);
                    }
                    else if (nWaitMSeond > 0)
                    {
                        m_cvCond.wait_for(lock, std::chrono::milliseconds(nWaitMSeond), [&]() {return this->m_bStop.load(); });
                    }
                }
            }
            }
        );
    }


private:
    std::atomic<bool> m_bStop;
    std::atomic<bool> m_bWork;
    std::condition_variable m_cvCond;
    std::mutex m_mtLock;
    std::thread m_thWork;

};

MessageQueue.hpp

template<class TData>
class MessageQueue
{
    using CallbackSignal = std::function<void(const TData& data)>;
    using CallbackTimeout = std::function<void()>;

    const static int kInfinite = -1;
public:
    MessageQueue()
        : m_bStop(false)
    {

    }

    ~MessageQueue()
    {
        Stop();
    }

    void Start(CallbackSignal cbNotify)
    {
        assert(cbNotify);
        Stop();
        m_bStop.store(false);
        m_thRun = std::thread([=] {
            while (!this->m_bStop.load())
            {
                std::mutex mt;
                std::unique_lock<std::mutex> lock(mt);
                m_cvSignal.wait(lock, [=] {
                    return !this->m_listData.empty() || this->m_bStop.load(); }
                );
                if (this->m_bStop.load())break;
                TData tmpData;
                if (cbNotify && PopFront(tmpData))
                {
                    cbNotify(tmpData);
                }
            }
            }
        );
    }

    void Start(CallbackSignal cbSignal, CallbackTimeout cbTimeout, int nWaitMSecond)
    {
        assert(cbSignal);
        Stop();
        m_bStop.store(false);
        m_thRun = std::thread([=] {
            while (!this->m_bStop.load())
            {
                std::mutex mt;
                std::unique_lock<std::mutex> lock(mt);
                bool bSucc = m_cvSignal.wait_for(lock, std::chrono::milliseconds(nWaitMSecond), [=] {
                    return !this->m_listData.empty() || this->m_bStop.load(); }
                );
                if (this->m_bStop.load()) break;
                if (bSucc)
                {
                    TData tmpData;
                    if (cbSignal && PopFront(tmpData))
                    {
                        cbSignal(tmpData);
                    }
                }
                else
                {
                    if (cbTimeout)
                    {
                        cbTimeout();
                    }
                }
            }
            }
        );
    }

    void Stop()
    {
        m_bStop.store(true);
        m_cvSignal.notify_one();
        if (m_thRun.joinable())
        {
            m_thRun.join();
        }
    }

    void PushFront(const TData& data)
    {
        std::lock_guard<std::mutex> lock(m_mtLock);
        m_listData.emplace_front(data);

        m_cvSignal.notify_one();
    }

    bool PopFront(TData& data)
    {
        std::lock_guard<std::mutex> lock(m_mtLock);
        if (m_listData.empty()) return false;
        data = std::move(m_listData.front());
        m_listData.pop_front();

        return true;
    }

    void PushBack(const TData& data)
    {
        std::lock_guard<std::mutex> lock(m_mtLock);
        m_listData.emplace_back(data);

        m_cvSignal.notify_one();
    }

    bool PopBack(TData& data)
    {
        std::lock_guard<std::mutex> lock(m_mtLock);
        if (m_listData.empty()) return false;
        data = std::move(m_listData.back());
        m_listData.pop_back();

        return true;
    }

    void Clear()
    {
        std::lock_guard<std::mutex> lock(m_mtLock);
        m_listData.clear();
    }

private:
    MessageQueue(const MessageQueue&) = delete;
    MessageQueue& operator=(const MessageQueue&) = delete;

    MessageQueue(const MessageQueue&&) = delete;
    MessageQueue& operator=(const MessageQueue&&) = delete;


private:
    std::atomic<bool> m_bStop;
    std::mutex m_mtLock;
    std::list<TData> m_listData;
    std::condition_variable m_cvSignal;
    std::thread m_thRun;

};

main.cpp

#include <iostream>
#include <vector>
#include <map>
#include <string>
#include "ThreadObject.hpp"
#include "MessageQueue.hpp"
#include <windows.h>


struct CommandInfo
{
    BYTE* lpBuffer;
    DWORD dwCmdID;
    CommandInfo* pPreCmd;
    CommandInfo* pNextCmd;
};

struct TestData
{
    int nNum = 0;
    int nDate = 1;
    void Print() const
    {
        //std::cout << "Data: " << nNum << "-" << nDate << "\n";
    }
};

struct MyData
{
    int nIndex = 0;
    std::string strData;
    std::vector<int> vecData;

 public:
    void Print() const
    {
        std::cout << "Index: " << nIndex << "[";
        for(const auto& item : vecData)
            std::cout << item << ",";
        std::cout << "]\n\n";
    }
};

class MyClass
{
public:
    MyClass()
        : m_nIndex(0)
    {
        //m_queMsg.Start(std::bind(&MyClass::do_print_data, this, std::placeholders::_1));
        m_queMsg.Start(std::bind(&MyClass::PopData, this, std::placeholders::_1));
        /*m_objThread1.Start(std::bind(&MyClass::run, this), 40);
        m_objThread.StartAndWait(std::bind(&MyClass::PushData, this), 50);*/
        
        m_objThread1.Start(std::bind(&MyClass::run, this), 40);
        m_objThread.StartAndWait(std::bind(&MyClass::PushData, this), 60);
    }

    ~MyClass()
    {
        Stop();
    }

    void Stop()
    {
        m_objThread1.Stop();
        m_objThread.Stop();
        m_queMsg.Stop();
    }

private:
    void run()
    {
        std::cout << "This is-- " << 999 << "--test\n";
        TestData* pData = new TestData;
        pData->nDate = 999;
        pData->nNum = 999;

        CommandInfo* cmd = new CommandInfo;
        cmd->lpBuffer = (BYTE*)pData;
        cmd->dwCmdID = 999;

        m_queMsg.PushBack(cmd);
        m_objThread.SetEvent();
        //std::cout << "This is-- " << ++m_nIndex << "--test\n";
        //
        m_queMsg.PushBack(m_nIndex);
        //MyData dataTmp;
        //dataTmp.nIndex = m_nIndex;
        //dataTmp.strData = std::to_string(m_nIndex);
        //for (int i = 0;i < m_nIndex;++i)
        //{
        //    dataTmp.vecData.push_back(i);
        //}
        //std::cout << sizeof(dataTmp) << std::endl;
        //m_queMsg.PushBack(dataTmp);
    }

    void do_print_data(/*const int& nData*/const MyData& data)
    {
        //std::cout << "[Callback] Fetch data " << nData << "\n";
        data.Print();
    }

    void PushData()
    {
        std::cout << "This is-- " << ++m_nIndex << "--test\n";
        TestData* pData = new TestData;
        pData->nDate = m_nIndex;
        pData->nNum = m_nIndex;

        CommandInfo* cmd = new CommandInfo;
        cmd->lpBuffer = (BYTE*)pData;
        cmd->dwCmdID = m_nIndex;

        m_queMsg.PushBack(cmd);
    }

    void PopData(CommandInfo* pCmd)
    {
        TestData* pData = (TestData*)pCmd->lpBuffer;
        pData->Print();

        delete pCmd->lpBuffer;
        pCmd->lpBuffer = nullptr;

        delete pCmd;
        pCmd = nullptr;
    }

private:
    MyClass(const MyClass&) = delete;
    MyClass& operator=(const MyClass&) = delete;

    MyClass(const MyClass&&) = delete;
    MyClass& operator=(const MyClass&&) = delete;


private:
    int m_nIndex;
    ThreadObject m_objThread;
    ThreadObject m_objThread1;
    //MessageQueue<int> m_queMsg;
    //MessageQueue<MyData> m_queMsg;
    MessageQueue<CommandInfo*> m_queMsg;
};


int main()
{
    std::cout << sizeof(MyData) << std::endl;
    MyClass objTest;
    std::this_thread::sleep_for(std::chrono::milliseconds(500));

    objTest.Stop();
    getchar();
    std::cout << "Application exit normal\n";

    return 0;
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值