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)