C++ 11实现 messagequeue, looper,handler

本文介绍了一个基于C++实现的消息队列和调度器的设计方案,包括Message、MessageQueue和Dispatcher等关键类的定义与功能实现,适用于多线程环境下的任务调度与消息传递。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

 

Message.h 可根据实际情况定义

#pragma once

#include <algorithm>
#include <iostream>
#include <memory>
#include <string>
#include <vector>
#include <functional>

class Dispatcher;
using std::string;

class Message: public std::enable_shared_from_this<Message> {
 friend class Dispatcher;
 private:
   int m_h;
   string get_message_name();

 public:
  virtual ~Message() = 0;
  string to_string();

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

  virtual bool isSameMessage(std::shared_ptr<Message> msg);

  void set_next_hop(Dispatcher* dispatcher) {
    m_next_hop = dispatcher;
  }

  Dispatcher* get_next_hop() {
    return m_next_hop;
  }

 protected:
  string mName;
  Dispatcher* m_next_hop;
};

inline string Message::get_message_name() { return mName; }
inline string Message::to_string() { return get_message_name(); }

looper是一个thread+一个Messagequeue

MyLooper.h

#pragma once
#ifndef _MY_LOOPER_H__
#define _MY_LOOPER_H__

#include <thread>

#include <shared_mutex>
#include "Message.h"
#include "MessageQueue.h"

class Dispatcher;

class MyLooper {
 protected:
  string mName;
  Dispatcher *mDispatcher;
  std::unique_ptr<MessageQueue> mMessageQueue;
  std::thread* mLooperThread;

 public:
  static constexpr bool FEATURE_DYNAMIC_THREAD = false;
  std::shared_timed_mutex looperMutex;
  std::condition_variable_any looperCv;
  bool isLooperReady;
  bool mExit;
  bool mReleaseThread;

  MyLooper();
  virtual ~MyLooper();

  void init(Dispatcher *dispatcher);
  void dispatch(std::shared_ptr<Message> msg);
  void dispatchSync(std::shared_ptr<Message> msg);
  void handleMessage(std::shared_ptr<Message> msg);
  void handleMessageSync(std::shared_ptr<Message> msg);

  size_t getSize();
  bool isEmptyQueue();
  void dumpMessageQueue();
  std::shared_ptr<Message> getFirstMessage();

  std::thread *getLooperThread();
  void acquireThread();
  void releaseThread();
  string to_string();

  void waitForLooperToConsumeAllMsgs();
  void killLooper();
};

inline MyLooper::MyLooper(){
    mExit = false;
    mLooperThread = nullptr;
    mMessageQueue = std::unique_ptr<MessageQueue>(new MessageQueue);
};

inline MyLooper::~MyLooper() {
  if (mMessageQueue) {
    mMessageQueue->clear();
  }
  killLooper();
  if (mLooperThread != nullptr) {
    mLooperThread->join();
    delete mLooperThread;
    mLooperThread = nullptr;
  }
  mMessageQueue = nullptr;
};

inline std::thread *MyLooper::getLooperThread() { return mLooperThread; }
inline string MyLooper::to_string() { return mName; }
#endif

MyLooper.cpp 


#include <thread>
#include <chrono>
#include "MyLooper.h"
#include "Dispatcher.h"


using std::condition_variable_any;
using std::lock_guard;
using std::unique_lock;
using std::thread;
using std::runtime_error;

void myLoop(MyLooper *instance) {
  string TAG = instance->to_string();
  //setThreadName(TAG.c_str());
  while (!instance->mExit) {
    {
      std::unique_lock<std::shared_timed_mutex> mylock(instance->looperMutex);
      instance->looperCv.wait(mylock,
                              [=] { return instance->isLooperReady == true; });
    }
    while (instance->isEmptyQueue() == false) {

      std::shared_ptr<Message> msg = instance->getFirstMessage();
      if(msg)
      {
        string msgName = msg->to_string();
        std::cout << "get first msg: "<< msgName << std::endl;
        instance->handleMessage(msg);
      }
    }
    {
      std::unique_lock<std::shared_timed_mutex> mylock(instance->looperMutex);
      if (instance->isEmptyQueue()) {
        instance->isLooperReady = false;
      }
    }
    instance->looperCv.notify_all();
    if (MyLooper::FEATURE_DYNAMIC_THREAD) {
      instance->releaseThread();
      break;
    }
  }
}

void MyLooper::dispatch(std::shared_ptr<Message> msg) {
  acquireThread();
  if (!mExit && mMessageQueue) {
    mMessageQueue->enqueue(msg);
  }
  {
    lock_guard<std::shared_timed_mutex> lock(looperMutex);
    isLooperReady = true;
  }
  looperCv.notify_all();
}

void MyLooper::dispatchSync(std::shared_ptr<Message> msg) {
  handleMessageSync(msg);
}

size_t MyLooper::getSize() {
  if (mMessageQueue) {
   return mMessageQueue->getSize();
  }
  return 0;
}

bool MyLooper::isEmptyQueue() {
  if (mMessageQueue) {
    return mMessageQueue->isEmpty();
  }
  return true;
}

void MyLooper::dumpMessageQueue() {
  if (mMessageQueue) {
    mMessageQueue->dumpMessageQueue();
  }
}

std::shared_ptr<Message> MyLooper::getFirstMessage() {
  if (mMessageQueue) {
    return mMessageQueue->pop();
  }
  return nullptr;
}

void MyLooper::init(Dispatcher *dispatcher) {
  mDispatcher = dispatcher;
  mName = mDispatcher->to_string() + "-Looper";
  if (mMessageQueue) {
    mMessageQueue->init(mDispatcher->to_string());
  }
}

void MyLooper::handleMessage(std::shared_ptr<Message> msg) {
  mDispatcher->handleMessage(msg);
}

void MyLooper::handleMessageSync(std::shared_ptr<Message> msg) {
  mDispatcher->handleMessageSync(msg);
}
  

void MyLooper::acquireThread() {
  std::lock_guard<std::shared_timed_mutex> lock(looperMutex);
  if (mLooperThread == nullptr && mExit == false) {
    mLooperThread = new std::thread ( myLoop, this );
  }
}

void MyLooper::releaseThread() {
  std::lock_guard<std::shared_timed_mutex> lock(looperMutex);
  if (MyLooper::FEATURE_DYNAMIC_THREAD) {
    if (mLooperThread != nullptr) {
      {
        std::lock_guard<std::shared_timed_mutex> lock(looperMutex);
        mReleaseThread = true;
        isLooperReady = true;
      }
      looperCv.notify_all();

      mLooperThread->join();
      delete mLooperThread;
      mLooperThread = nullptr;
    }
  }
}

void MyLooper::waitForLooperToConsumeAllMsgs() {
  while (true) {
    {
      std::unique_lock<std::shared_timed_mutex> mylock(looperMutex);
      looperCv.wait(mylock, [&] { return isLooperReady == false; });
    }
    if (isEmptyQueue()) {
      std::this_thread::sleep_for(std::chrono::seconds(2));
      return;
    }
  }
}

void MyLooper::killLooper() {
  {
    std::lock_guard<std::shared_timed_mutex> lock(looperMutex);
    mExit = true;
    isLooperReady = true;
  }
  looperCv.notify_all();
}

MessageQueue.h

#pragma once
#include <deque>
#include <shared_mutex>
#include "Message.h"

using std::deque;

class Message;
class MessageQueue {
 protected:
  string mName;
  std::shared_timed_mutex mMutex;
  deque<std::shared_ptr<Message> > mMessages;

 public:
  MessageQueue();
  virtual ~MessageQueue() {}
  virtual void init(string name) { mName = name + "-MessageQueue"; }
  virtual void enqueue(std::shared_ptr<Message> msg);
  virtual size_t getSize();
  virtual void dumpMessageQueue();
  virtual bool isEmpty();
  virtual void clear();
  virtual std::shared_ptr<Message> pop();
  string to_string();

  // void dump();
};

inline MessageQueue::MessageQueue() = default;
inline string MessageQueue::to_string() { return mName; }

MessageQueue.cpp

#include "MessageQueue.h"
#include <shared_mutex>
using std::lock_guard;

void MessageQueue::enqueue(std::shared_ptr<Message> msg) {
  if(msg == nullptr){
    return;
  }
  lock_guard<std::shared_timed_mutex> lock(mMutex);
  mMessages.push_back(msg);
  mMessages.shrink_to_fit();
}

size_t MessageQueue::getSize() {
  lock_guard<std::shared_timed_mutex> lock(mMutex);
  return mMessages.size();
}

bool MessageQueue::isEmpty() {
  lock_guard<std::shared_timed_mutex> lock(mMutex);
  return mMessages.empty();
}

void MessageQueue::dumpMessageQueue() {
  lock_guard<std::shared_timed_mutex> lock(mMutex);
  for (auto& elem : mMessages) {
    printf("[%s]: dequeued message %p", to_string().c_str(), elem.get());
  }
}

void MessageQueue::clear() {
  lock_guard<std::shared_timed_mutex> lock(mMutex);
  mMessages.clear();
}

std::shared_ptr<Message> MessageQueue::pop() {
  if(getSize() > 0) {
    lock_guard<std::shared_timed_mutex> lock(mMutex);
    std::shared_ptr<Message> msg = mMessages.front();
    mMessages.pop_front();
    mMessages.shrink_to_fit();
    return msg;
  } else {
      return nullptr;
  }
}

 处理handler,命名为

 Dispatcher.h

#pragma once
#ifndef __Dispatcher_H__
#define __Dispatcher_H__

#include <memory>
#include <functional>
#include <string>
#include <thread>
//#include <unordered_map>
#include <iostream>

#include "MyLooper.h"
#include "Message.h"
#include "MessageQueue.h"

#define HANDLER(MSG_TYPE, FUNC) {REG_MSG(MSG_TYPE::MESSAGE_NAME), ([this](auto msg) { Module::handler<MSG_TYPE>(std::bind(&FUNC, this, std::placeholders::_1), msg); })}
#define HANDLER_MULTI(MSG_TYPE, name, FUNC) {REG_MSG(name), ([this](auto msg) { Module::handler<MSG_TYPE>(std::bind(&FUNC, this, std::placeholders::_1), msg); })}


class Dispatcher: public std::enable_shared_from_this<Dispatcher> {
 protected:
  std::string mName;
  std::unique_ptr<MyLooper> mLooper;
  /*std::unordered_map<message_id_t,
                     std::function<void(std::shared_ptr<Message>)>,
                     std::hash<message_id_t>,
                     std::equal_to<message_id_t>
                     > */

 public:
  Dispatcher();
  virtual ~Dispatcher();
  virtual void init();
  void dispatch(std::shared_ptr<Message> msg);
  void dispatchSync(std::shared_ptr<Message> msg);
  void handleMessage(std::shared_ptr<Message> msg);
  void handleMessageSync(std::shared_ptr<Message> msg);

  void onMessageArrival(std::shared_ptr<Message> msg);

  string to_string();
  std::thread *getLooperThread();
  size_t getUnProcessedMessageCount();
  bool hasValidLooper();

  template<class M>
  inline void handler(std::function<void(std::shared_ptr<M>)> f, std::shared_ptr<Message> msg) {
    auto event = std::static_pointer_cast<M> (msg);
    f(event);
  }

  void waitForLooperToConsumeAllMsgs();
  void killLooper();

};

inline Dispatcher::Dispatcher() = default;

template <typename M>
class load_Dispatcher
{
    public:
        load_Dispatcher() {
            get_Dispatcher().init();
        }
        M &get_Dispatcher() {
            static M dispatcher{};
            return dispatcher;
        }
};

#endif

Dispatcher.cpp

#include "Dispatcher.h"

using std::lock_guard;
using namespace std;

void Dispatcher::onMessageArrival(std::shared_ptr<Message> msg) {
  if (mLooper != nullptr) {
    mLooper->dispatch(msg);
  }
}

void Dispatcher::dispatch(std::shared_ptr<Message> msg) {
  if (!msg->get_next_hop()) {
    msg->set_next_hop(this);
  }

  if (mLooper != nullptr) {
    mLooper->dispatch(msg);
  }
}

void Dispatcher::dispatchSync(std::shared_ptr<Message> msg) {
  if (mLooper != nullptr) {
    mLooper->dispatchSync(msg);
  }
}

void Dispatcher::handleMessage(std::shared_ptr<Message> msg) {
    cout<<"handle msg: "<< msg->to_string()<< endl;
}

void Dispatcher::handleMessageSync(std::shared_ptr<Message> msg) {
    cout<<"handle msg sync: "<< msg->to_string()<< endl;
}

void Dispatcher::init() {
  if (mLooper != nullptr) {
    mLooper->init(this);
  }
}

Dispatcher::~Dispatcher() {
    mLooper = nullptr;
}

std::thread *Dispatcher::getLooperThread() {
  if (mLooper != nullptr) {
    return mLooper->getLooperThread();
  } else {
    return nullptr;
  }
}

bool Dispatcher::hasValidLooper() {
  if (mLooper != nullptr) {
    return true;
  }
  return false;
}

size_t Dispatcher::getUnProcessedMessageCount() {
  if (mLooper != nullptr) {
    return mLooper->getSize();
  }
  return 0;
}

void Dispatcher::waitForLooperToConsumeAllMsgs() {
  if (mLooper != nullptr) {
    mLooper->waitForLooperToConsumeAllMsgs();
  }
}

void Dispatcher::killLooper() {
  if (mLooper != nullptr) {
    mLooper->killLooper();
  }
}

string Dispatcher::to_string() { return mName; }

可以根据自己的需要,写对应的main.cpp,以及客制化message

#include "Dispatcher.h"
#include <iostream>

using namespace std;

int main() {
    Dispatcher dispatcher;
    dispatcher.init();
    //auto msg = std::make_shared<MyMessage>(string("msg1"));
    cout<<"fine"<<endl;
    return 0;
}

提供一个参考的Makefile文件:


######### Makefile COMMON ########
#c or c++
EXTENSION = cpp
#gcc or g++
CC = g++
#exe name
EXE = main
#source-file-direction space add-more-as: src src1 src2
SUBDIR = src
#.o file direction
OBJ_DIR = obj
#.d file direction
DEP = dep
 
#(including .h file direction)
CPPFLAGS += -I ./inc

# link flags
LDFLAGS += -pthread
#
CFLAGS += -g -Wall -O2 \
          -fsanitize=address
 
#not change lines below

CXX_SOURCES = $(foreach dir,$(SUBDIR), $(wildcard $(dir)/*.$(EXTENSION)))
CXX_OBJECTS = $(patsubst  %.$(EXTENSION), $(OBJ_DIR)/%.o, $(notdir $(CXX_SOURCES)))
DEP_FILES  = $(patsubst  %.$(EXTENSION), $(DEP)/%.d, $(notdir $(CXX_SOURCES)))


$(EXE): $(CXX_OBJECTS)
	$(CC) $(CFLAGS) $(LDFLAGS) $(CXX_OBJECTS) -o $(EXE)
 
$(OBJ_DIR)/%.o: $(SUBDIR)/%.$(EXTENSION)
	if [ ! -d $(OBJ_DIR) ]; then mkdir -p $(OBJ_DIR); fi;\
	$(CC) -c $(CFLAGS) $(CPPFLAGS) $< -o $@
 
$(DEP)/%.d: $(SUBDIR)/%.$(EXTENSION)
	if [ ! -d $(OBJ_DIR) ]; then mkdir -p $(OBJ_DIR); fi;\
	$(CC) $(CFLAGS) $(CPPFLAGS) -MM $< | sed -e 1's,^,$(OBJ_DIR)/,' > $@
 

ifneq "$(MAKECMDGOALS)" "clean"
-include $(DEP_FILES)
endif
 
.PHONY:clean
clean:
	rm -rf $(OBJ_DIR)  $(EXE)

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值