C++软件开发架构

文章目录

      • 1.全局消息通信
        • MsgHandler.h
        • 单元测试(QTest)
          • MsgHandlerUnitTest.h
          • MsgHandlerUnitTest.cpp
      • 2.实例间通信
        • InstMsgHandler.h
        • 单元测试
          • InstMsgHandlerUnitTest.h
          • InstMsgHandlerUnitTest.cpp

1.全局消息通信

1. 适用于类与类单个对象实例之间的通信,多个对象需要酌情使用
2. 支持优先级触发
3. 支持附带参数
4. 支持异步执行
5. 使用方式可以查看下方单元测试代码
MsgHandler.h
#pragma once#include <functional>
#include <unordered_map>
#include <map>
#include <string>
#include "any.h"class MsgHandler {
#ifdef _DEBUGusing MsgType = std::string;
#elseusing MsgType = const char*;
#endiffriend class MsgHandlerUnitTest;
public:static MsgHandler* GetInstance() {static MsgHandler i;return &i;}void SetAsyncExecFunc(std::function<void(std::function<void()>)> func) { asyncExecFunc_ = func; }void SetMainExecFunc(std::function<void(std::function<void()>)> func) { mainExecFunc_ = func; }void TriggerMsg_(MsgType msg, std::any info = std::any{}) {ExecMsgHandler(msg, defaultExecFunc_, info);}void AsyncExecMsg_(MsgType msg, std::any info = std::any{}) {if(!asyncExecFunc_) throw std::runtime_error("dont set async exec func");ExecMsgHandler(msg, asyncExecFunc_, info);}void MainExecMsg_(MsgType msg, std::any info = std::any{}) {if (!mainExecFunc_) throw std::runtime_error("dont set main exec func");ExecMsgHandler(msg, mainExecFunc_, info);}void RegisterMsgHandler_(MsgType msg, void* t, std::function<void(std::any)> func, int priority = 0) {globalMsgHandler_[msg][priority].insert({ t, func });}void RegisterMsgHandler_(MsgType msg, void* t, std::function<void()> func, int priority = 0) {globalMsgHandler_[msg][priority].insert({ t, [=](std::any) {func(); } });}void Deregister_(void* t) {for (auto& msgHandler : globalMsgHandler_) {PriorityMap& priorityMap = msgHandler.second;for (auto& priorityEntry : priorityMap) {HandlerMap& handlerMap = priorityEntry.second;handlerMap.erase(t);}}}
private:void ExecMsgHandler(MsgType msg, std::function<void(std::function<void()>)> func, std::any info = std::any{}) {auto it = globalMsgHandler_.find(msg);if (it != globalMsgHandler_.end()) {PriorityMap& priorityMap = it->second;for (auto& priorityEntry : priorityMap) {HandlerMap& handlerMap = priorityEntry.second;for (auto& handlerEntry : handlerMap) {std::function<void(std::any)>& handler = handlerEntry.second;func([&handler, info] {handler(info); });}}}}
private:MsgHandler() = default;using HandlerMap = std::unordered_map<void*, std::function<void(std::any)>>;using PriorityMap = std::map<int, HandlerMap, std::greater<int>>;std::function<void(std::function<void()>)> defaultExecFunc_ = [](std::function<void()> func) { func(); };std::function<void(std::function<void()>)> asyncExecFunc_;std::function<void(std::function<void()>)> mainExecFunc_;std::unordered_map<MsgType, PriorityMap> globalMsgHandler_;
};#define RegisterMsgHandler(msg, ...) MsgHandler::GetInstance()->RegisterMsgHandler_(#msg, this, __VA_ARGS__)
#define TriggerMsg(msg, ...) MsgHandler::GetInstance()->TriggerMsg_(#msg, __VA_ARGS__)
#define AsyncExecMsg(msg, ...)  MsgHandler::GetInstance()->AsyncExecMsg_(#msg, __VA_ARGS__)
#define MainExecMsg(msg, ...)  MsgHandler::GetInstance()->MainExecMsg_(#msg, __VA_ARGS__)
#define Deregister() MsgHandler::GetInstance()->Deregister_(this)
单元测试(QTest)
MsgHandlerUnitTest.h
#include <QTest>
#include <vector>class MsgHandlerUnitTest :public QObject {Q_OBJECT
private slots:void initTestCase();void cleanupTestCase();void init();void cleanup();void RegisterTest();void DeregisterTest();void PriorityPreTest();void PriorityTest();void TriggerNoParamTest();void TriggerHasParamTest();void AsyncTriggerTest();void MainTriggerTest();void MemoryLeakTest();
private:bool VarifyResult();
private:std::vector<bool> m_results;
};
MsgHandlerUnitTest.cpp
#include "MsgHandlerUnitTest.h"
#include "MsgHandler.h"
#include <QTimer>class RunnableTask : public QRunnable {
public:RunnableTask(std::function<void()> func) : func_(func) {setAutoDelete(true);}void run() { func_(); }
private:std::function<void()> func_;
};class AsyncThreadPool {
public:void AddTask(std::function<void()> func) {QThreadPool::globalInstance()->start(new RunnableTask(func));}
public:static AsyncThreadPool* GetInstance() {static AsyncThreadPool i;return &i;}
private:AsyncThreadPool() = default;
};
#define GAsyncThreadPool AsyncThreadPool::GetInstance()int GetCurMemoryKB()
{SetProcessWorkingSetSize(GetCurrentProcess(), -1, -1);PROCESS_MEMORY_COUNTERS pmc;GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc));auto curMemoryKB = pmc.WorkingSetSize / 1024;return curMemoryKB;
}enum Msg {A,B,C,
};void MsgHandlerUnitTest::RegisterTest()
{struct ClassA {ClassA() {RegisterMsgHandler(Msg::A, [this] {});RegisterMsgHandler(Msg::B, [this](const std::any& data) {});}~ClassA() {Deregister();}};struct ClassB {ClassB() {RegisterMsgHandler(Msg::A, [this] {});RegisterMsgHandler(Msg::B, [this](const std::any& data) {});}~ClassB() {Deregister();}};ClassA a1;const auto& globalMsgHandler = MsgHandler::GetInstance()->globalMsgHandler_;m_results.push_back(globalMsgHandler.size() == 2);m_results.push_back(globalMsgHandler.at("Msg::A").size() == 1);m_results.push_back(globalMsgHandler.at("Msg::B").size() == 1);m_results.push_back(globalMsgHandler.at("Msg::A").at(0).size() == 1);m_results.push_back(globalMsgHandler.at("Msg::B").at(0).size() == 1);ClassA a2;m_results.push_back(globalMsgHandler.size() == 2);m_results.push_back(globalMsgHandler.at("Msg::A").size() == 1);m_results.push_back(globalMsgHandler.at("Msg::B").size() == 1);m_results.push_back(globalMsgHandler.at("Msg::A").at(0).size() == 2);m_results.push_back(globalMsgHandler.at("Msg::B").at(0).size() == 2);ClassB b1;m_results.push_back(globalMsgHandler.size() == 2);m_results.push_back(globalMsgHandler.at("Msg::A").size() == 1);m_results.push_back(globalMsgHandler.at("Msg::B").size() == 1);m_results.push_back(globalMsgHandler.at("Msg::A").at(0).size() == 3);m_results.push_back(globalMsgHandler.at("Msg::B").at(0).size() == 3);QVERIFY(VarifyResult());
}void MsgHandlerUnitTest::DeregisterTest() {struct ClassA {ClassA() {RegisterMsgHandler(Msg::A, [this] {});RegisterMsgHandler(Msg::B, [this](const std::any& data) {});}~ClassA() {Deregister();}};const auto& globalMsgHandler = MsgHandler::GetInstance()->globalMsgHandler_;{ClassA a1;m_results.push_back(globalMsgHandler.size() == 2);m_results.push_back(globalMsgHandler.at("Msg::A").size() == 1);m_results.push_back(globalMsgHandler.at("Msg::B").size() == 1);m_results.push_back(globalMsgHandler.at("Msg::A").at(0).size() == 1);m_results.push_back(globalMsgHandler.at("Msg::B").at(0).size() == 1);}m_results.push_back(globalMsgHandler.size() == 2);m_results.push_back(globalMsgHandler.at("Msg::A").size() == 1);m_results.push_back(globalMsgHandler.at("Msg::B").size() == 1);m_results.push_back(globalMsgHandler.at("Msg::A").at(0).size() == 0);m_results.push_back(globalMsgHandler.at("Msg::B").at(0).size() == 0);QVERIFY(VarifyResult());
}void MsgHandlerUnitTest::PriorityPreTest() {struct ClassA {ClassA() {RegisterMsgHandler(Msg::A, [this] {});RegisterMsgHandler(Msg::B, [this](const std::any& data) {});}~ClassA() {Deregister();}};struct ClassB {ClassB() {RegisterMsgHandler(Msg::A, [this] {}, 1);RegisterMsgHandler(Msg::B, [this](const std::any& data) {}, 1);}~ClassB() {Deregister();}};const auto& globalMsgHandler = MsgHandler::GetInstance()->globalMsgHandler_;ClassA a1;m_results.push_back(globalMsgHandler.size() == 2);m_results.push_back(globalMsgHandler.at("Msg::A").size() == 1);m_results.push_back(globalMsgHandler.at("Msg::B").size() == 1);m_results.push_back(globalMsgHandler.at("Msg::A").at(0).size() == 1);m_results.push_back(globalMsgHandler.at("Msg::B").at(0).size() == 1);ClassA a2;m_results.push_back(globalMsgHandler.size() == 2);m_results.push_back(globalMsgHandler.at("Msg::A").size() == 1);m_results.push_back(globalMsgHandler.at("Msg::B").size() == 1);m_results.push_back(globalMsgHandler.at("Msg::A").at(0).size() == 2);m_results.push_back(globalMsgHandler.at("Msg::B").at(0).size() == 2);ClassB b;m_results.push_back(globalMsgHandler.size() == 2);m_results.push_back(globalMsgHandler.at("Msg::A").size() == 2);m_results.push_back(globalMsgHandler.at("Msg::B").size() == 2);m_results.push_back(globalMsgHandler.at("Msg::A").at(0).size() == 2);m_results.push_back(globalMsgHandler.at("Msg::B").at(0).size() == 2);m_results.push_back(globalMsgHandler.at("Msg::A").at(1).size() == 1);m_results.push_back(globalMsgHandler.at("Msg::B").at(1).size() == 1);QVERIFY(VarifyResult());
}
std::vector<int> priorityTestvec;
void MsgHandlerUnitTest::PriorityTest()
{struct ClassA {ClassA() {RegisterMsgHandler(Msg::A, [this] {priorityTestvec.push_back(a);});RegisterMsgHandler(Msg::B, [this] {priorityTestvec.push_back(a);}, 1);}~ClassA() {Deregister();}int a = 5;};struct ClassB {ClassB() {RegisterMsgHandler(Msg::A, [this] {priorityTestvec.push_back(b);}, 1);RegisterMsgHandler(Msg::B, [this] {priorityTestvec.push_back(b);});}~ClassB() {Deregister();}int b = 10;};ClassA a;ClassB b;priorityTestvec.clear();TriggerMsg(Msg::A);m_results.push_back(priorityTestvec.size() == 2);m_results.push_back(priorityTestvec[0] == 10 && priorityTestvec[1] == 5);priorityTestvec.clear();TriggerMsg(Msg::B);m_results.push_back(priorityTestvec.size() == 2);m_results.push_back(priorityTestvec[0] == 5 && priorityTestvec[1] == 10);QVERIFY(VarifyResult());
}void MsgHandlerUnitTest::TriggerNoParamTest()
{struct ClassA {ClassA() {RegisterMsgHandler(Msg::A, [this] {a = A;});RegisterMsgHandler(Msg::B, [this] {a = B;});}~ClassA() {Deregister();}int a = 0;};struct ClassB {ClassB() {RegisterMsgHandler(Msg::A, [this] {b = A;});RegisterMsgHandler(Msg::B, [this] {b = B;});}~ClassB() {Deregister();}int b = 0;};const auto& globalMsgHandler = MsgHandler::GetInstance()->globalMsgHandler_;ClassA a1;ClassB b1;m_results.push_back(a1.a == 0);m_results.push_back(b1.b == 0);TriggerMsg(Msg::A);m_results.push_back(a1.a == A);m_results.push_back(b1.b == A);TriggerMsg(Msg::B);m_results.push_back(a1.a == B);m_results.push_back(b1.b == B);QVERIFY(VarifyResult());
}void MsgHandlerUnitTest::TriggerHasParamTest()
{struct ClassA {ClassA() {RegisterMsgHandler(Msg::C, [this](const std::any& data) {a = std::any_cast<int>(data);});}~ClassA() {Deregister();}int a = 0;};struct ClassB {ClassB() {RegisterMsgHandler(Msg::C, [this](const std::any& data) {b = std::any_cast<int>(data);});}~ClassB() {Deregister();}int b = 0;};const auto& globalMsgHandler = MsgHandler::GetInstance()->globalMsgHandler_;ClassA a1;ClassB b1;m_results.push_back(a1.a == 0);m_results.push_back(b1.b == 0);TriggerMsg(Msg::C, 5);m_results.push_back(a1.a == 5);m_results.push_back(b1.b == 5);TriggerMsg(Msg::C, 999);m_results.push_back(a1.a == 999);m_results.push_back(b1.b == 999);QVERIFY(VarifyResult());
}std::vector<std::thread::id> AsyncTriggerTestVec;
void MsgHandlerUnitTest::AsyncTriggerTest()
{AsyncTriggerTestVec.push_back(std::this_thread::get_id());struct ClassA {ClassA() {RegisterMsgHandler(Msg::A, [this] {AsyncTriggerTestVec.push_back(std::this_thread::get_id());});}~ClassA() {Deregister();}};ClassA a;AsyncExecMsg(Msg::A);while (AsyncTriggerTestVec.size() != 2) {QCoreApplication::processEvents();}m_results.push_back(AsyncTriggerTestVec[0] != AsyncTriggerTestVec[1]);QVERIFY(VarifyResult());
}std::vector<std::thread::id> MainTriggerTestVec;
void MsgHandlerUnitTest::MainTriggerTest()
{MainTriggerTestVec.clear();MainTriggerTestVec.push_back(std::this_thread::get_id());struct ClassA {ClassA() {RegisterMsgHandler(Msg::A, [this] {MainTriggerTestVec.push_back(std::this_thread::get_id());MainExecMsg(Msg::B);});RegisterMsgHandler(Msg::B, [this] {MainTriggerTestVec.push_back(std::this_thread::get_id());});}~ClassA() {Deregister();}};ClassA a;AsyncExecMsg(Msg::A);while (MainTriggerTestVec.size() != 3) {QCoreApplication::processEvents();}m_results.push_back(MainTriggerTestVec[0] != MainTriggerTestVec[1] && MainTriggerTestVec[1] != MainTriggerTestVec[2] && MainTriggerTestVec[0] == MainTriggerTestVec[2]);QVERIFY(VarifyResult());
}void MsgHandlerUnitTest::MemoryLeakTest()
{struct ClassA {ClassA() {RegisterMsgHandler(Msg::A, [this] {a = A;});RegisterMsgHandler(Msg::B, [this] {a = B;});RegisterMsgHandler(Msg::C, [this](const std::any& data) {a = std::any_cast<int>(data);});}~ClassA() {Deregister();}int a = 0;};const auto& globalMsgHandler = MsgHandler::GetInstance()->globalMsgHandler_;auto beginMemory = GetCurMemoryKB();{std::vector<ClassA*> vec;for (int i = 0; i < 100000; ++i) {vec.push_back(new ClassA);}m_results.push_back(globalMsgHandler.size() == 3);m_results.push_back(globalMsgHandler.at("Msg::A").size() == 1);m_results.push_back(globalMsgHandler.at("Msg::B").size() == 1);m_results.push_back(globalMsgHandler.at("Msg::C").size() == 1);m_results.push_back(globalMsgHandler.at("Msg::A").at(0).size() == 100000);m_results.push_back(globalMsgHandler.at("Msg::B").at(0).size() == 100000);m_results.push_back(globalMsgHandler.at("Msg::C").at(0).size() == 100000);for (auto& v : vec) {delete v;}vec.clear();m_results.push_back(globalMsgHandler.size() == 3);m_results.push_back(globalMsgHandler.at("Msg::A").size() == 1);m_results.push_back(globalMsgHandler.at("Msg::B").size() == 1);m_results.push_back(globalMsgHandler.at("Msg::C").size() == 1);m_results.push_back(globalMsgHandler.at("Msg::A").at(0).size() == 0);m_results.push_back(globalMsgHandler.at("Msg::B").at(0).size() == 0);m_results.push_back(globalMsgHandler.at("Msg::C").at(0).size() == 0);}auto endMemory = GetCurMemoryKB();QVERIFY(endMemory - beginMemory < 30);
}bool MsgHandlerUnitTest::VarifyResult()
{bool result = true;for (auto& rlt : m_results) {if (!rlt) {result = false;break;}}return result;
}void MsgHandlerUnitTest::initTestCase()
{MsgHandler::GetInstance()->SetAsyncExecFunc([](std::function<void()> func) { GAsyncThreadPool->AddTask(func); });MsgHandler::GetInstance()->SetMainExecFunc([](std::function<void()> func) { QTimer::singleShot(0, qApp, func); });
}void MsgHandlerUnitTest::cleanupTestCase()
{
}void MsgHandlerUnitTest::init()
{m_results.clear();MsgHandler::GetInstance()->globalMsgHandler_.clear();
}void MsgHandlerUnitTest::cleanup()
{
}

2.实例间通信

1. 适用于类与类相互关联的对象之间的通信
2. 不支持优先级触发
3. 支持附带参数
4. 不支持异步执行
5. 使用方式可以查看下方单元测试代码
InstMsgHandler.h
#pragma once#include <unordered_map>
#include <functional>
#include <unordered_set>
#include "any.h"class InstMsgHandler {
#ifdef _DEBUGusing MsgType = std::string;
#elseusing MsgType = const char*;
#endiffriend class InstMsgHandlerUnitTest;
public:static InstMsgHandler* GetInstance() {static InstMsgHandler i;return &i;}void XTriggerMsg_(MsgType msg, void* trigger, std::any info = std::any{}) {auto findHandler = globalMsgHandler_.find(msg);if (findHandler != globalMsgHandler_.end()) {auto& handlers = findHandler->second;auto it = communicators_.find(trigger);if (it != communicators_.end()) {for (const auto& communicator : it->second) {auto handler = handlers.find(communicator);if (handler != handlers.end()) {handler->second(info);}}}}}void XRegisterMsgHandler_(MsgType msg, void* t, std::function<void(std::any)> func) {globalMsgHandler_[msg].insert({ t, func });}void XRegisterMsgHandler_(MsgType msg, void* t, std::function<void()> func) {globalMsgHandler_[msg].insert({ t, [=](std::any) {func(); } });}void XConnect_(void* c1, void* c2) {if (c1 == c2) {communicators_[c1].insert(c2);return;}communicators_[c1].insert(c2);communicators_[c2].insert(c1);}void XDisconnect_(void* c1, void* c2) {if (c1 == c2) {communicators_[c1].erase(c2);return;}communicators_[c1].erase(c2);communicators_[c2].erase(c1);}void XDeregister_(void* t) {XDisconnect_(t);DeregisterMsgHandler(t);}
private:void XDisconnect_(void* t) {auto it = communicators_.find(t);if (it != communicators_.end()) {auto communicators = it->second;for (auto communicator : communicators) {communicators_[communicator].erase(t);}}communicators_.erase(t);}void DeregisterMsgHandler(void* t) {for (auto& msgHandler : globalMsgHandler_) {HandlerMap& handlerMap = msgHandler.second;handlerMap.erase(t);}}
private:InstMsgHandler() = default;using HandlerMap = std::unordered_map<void*, std::function<void(std::any)>>;std::unordered_map<void*, std::unordered_set<void*>> communicators_;std::unordered_map<MsgType, HandlerMap> globalMsgHandler_;
};#define EXPAND(...) __VA_ARGS__
#define COUNT_ARGS_IMPL(_1, _2, _3, N, ...) N
#define COUNT_ARGS(...) EXPAND(COUNT_ARGS_IMPL(__VA_ARGS__, 3, 2, 1, 0))
#define XCONNECT_IMPL_1(a) InstMsgHandler::GetInstance()->XConnect_(this, a)
#define XCONNECT_IMPL_2(a, b) InstMsgHandler::GetInstance()->XConnect_(a, b)
#define XCONNECT_IMPL(n) XCONNECT_IMPL_##n
#define XCONNECT_DISPATCH(n, ...) EXPAND(XCONNECT_IMPL(n)(__VA_ARGS__))
#define XConnect(...) XCONNECT_DISPATCH(EXPAND(COUNT_ARGS(__VA_ARGS__)), __VA_ARGS__)#define XDISCONNECT_IMPL_1(a) InstMsgHandler::GetInstance()->XDisconnect_(this, a)
#define XDISCONNECT_IMPL_2(a, b) InstMsgHandler::GetInstance()->XDisconnect_(a, b)
#define XDISCONNECT_IMPL(n) XDISCONNECT_IMPL_##n
#define XDISCONNECT_DISPATCH(n, ...) EXPAND(XDISCONNECT_IMPL(n)(__VA_ARGS__))
#define XDisconnect(...) XDISCONNECT_DISPATCH(EXPAND(COUNT_ARGS(__VA_ARGS__)), __VA_ARGS__)#define XRegisterMsgHandler(msg, ...) InstMsgHandler::GetInstance()->XRegisterMsgHandler_(#msg, this, __VA_ARGS__)
#define XTriggerMsg(msg, ...) InstMsgHandler::GetInstance()->XTriggerMsg_(#msg, this, __VA_ARGS__)
#define XDeregister() InstMsgHandler::GetInstance()->XDeregister_(this)
单元测试
InstMsgHandlerUnitTest.h
#include <QTest>
#include <vector>class InstMsgHandlerUnitTest :public QObject {Q_OBJECT
private slots:void initTestCase();void cleanupTestCase();void init();void cleanup();void RegisterTest();void DeregisterTest();void XConnectABTest();void XDisconnectABTest();void ABTriggerNoParamTest();void ABTriggerHasParamTest();void XConnectBaseTest();void BaseTriggerNoParamTest();void BaseTriggerHasParamTest();void MemoryLeakTest();void BaseMemoryLeakTest();
private:bool VarifyResult();
private:std::vector<bool> m_results;
};
InstMsgHandlerUnitTest.cpp
#include "InstMsgHandlerUnitTest.h"
#include "InstMsgHandler.h"int GetCurMemoryKB()
{SetProcessWorkingSetSize(GetCurrentProcess(), -1, -1);PROCESS_MEMORY_COUNTERS pmc;GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc));auto curMemoryKB = pmc.WorkingSetSize / 1024;return curMemoryKB;
}enum Msg {A,B,C,
};void InstMsgHandlerUnitTest::RegisterTest()
{struct ClassA {ClassA() {XRegisterMsgHandler(Msg::A, [this] {});XRegisterMsgHandler(Msg::B, [this](const std::any& data) {});}~ClassA() {XDeregister();}};struct ClassB {ClassB() {XRegisterMsgHandler(Msg::A, [this] {});XRegisterMsgHandler(Msg::B, [this](const std::any& data) {});}~ClassB() {XDeregister();}};ClassA a;const auto& globalMsgHandler = InstMsgHandler::GetInstance()->globalMsgHandler_;m_results.push_back(globalMsgHandler.size() == 2);m_results.push_back(globalMsgHandler.at("Msg::A").size() == 1);m_results.push_back(globalMsgHandler.at("Msg::B").size() == 1);ClassB b;m_results.push_back(globalMsgHandler.size() == 2);m_results.push_back(globalMsgHandler.at("Msg::A").size() == 2);m_results.push_back(globalMsgHandler.at("Msg::B").size() == 2);QVERIFY(VarifyResult());
}void InstMsgHandlerUnitTest::DeregisterTest() 
{struct ClassA {ClassA() {XRegisterMsgHandler(Msg::A, [this] {});XRegisterMsgHandler(Msg::B, [this](const std::any& data) {});}~ClassA() {XDeregister();}};struct ClassB {ClassB() {XRegisterMsgHandler(Msg::A, [this] {});XRegisterMsgHandler(Msg::B, [this](const std::any& data) {});}~ClassB() {XDeregister();}};const auto& globalMsgHandler = InstMsgHandler::GetInstance()->globalMsgHandler_;const auto& communicators = InstMsgHandler::GetInstance()->communicators_;{ClassA a;m_results.push_back(globalMsgHandler.size() == 2);m_results.push_back(globalMsgHandler.at("Msg::A").size() == 1);m_results.push_back(globalMsgHandler.at("Msg::B").size() == 1);m_results.push_back(communicators.size() == 0);{ClassB b;m_results.push_back(globalMsgHandler.size() == 2);m_results.push_back(globalMsgHandler.at("Msg::A").size() == 2);m_results.push_back(globalMsgHandler.at("Msg::B").size() == 2);XConnect(&a, &b);m_results.push_back(communicators.size() == 2);m_results.push_back(communicators.at(&a).size() == 1);m_results.push_back(communicators.at(&b).size() == 1);}m_results.push_back(globalMsgHandler.size() == 2);m_results.push_back(globalMsgHandler.at("Msg::A").size() == 1);m_results.push_back(globalMsgHandler.at("Msg::B").size() == 1);m_results.push_back(communicators.size() == 1);m_results.push_back(communicators.at(&a).size() == 0);}m_results.push_back(communicators.size() == 0);m_results.push_back(globalMsgHandler.size() == 2);m_results.push_back(globalMsgHandler.at("Msg::A").size() == 0);m_results.push_back(globalMsgHandler.at("Msg::B").size() == 0);QVERIFY(VarifyResult());
}void InstMsgHandlerUnitTest::XConnectABTest()
{struct ClassA {ClassA() {XRegisterMsgHandler(Msg::A, [this] {});XRegisterMsgHandler(Msg::B, [this](const std::any& data) {});}~ClassA() {XDeregister();}};struct ClassB {ClassB() {XRegisterMsgHandler(Msg::A, [this] {});XRegisterMsgHandler(Msg::B, [this](const std::any& data) {});}~ClassB() {XDeregister();}};ClassA a;ClassB b;XConnect(&a, &b);const auto& globalMsgHandler = InstMsgHandler::GetInstance()->globalMsgHandler_;const auto& communicators = InstMsgHandler::GetInstance()->communicators_;m_results.push_back(globalMsgHandler.size() == 2);m_results.push_back(globalMsgHandler.at("Msg::A").size() == 2);m_results.push_back(globalMsgHandler.at("Msg::B").size() == 2);m_results.push_back(communicators.size() == 2);m_results.push_back(communicators.at(&a).size() == 1);m_results.push_back(communicators.at(&b).size() == 1);QVERIFY(VarifyResult());
}void InstMsgHandlerUnitTest::XDisconnectABTest()
{struct ClassA {ClassA() {XRegisterMsgHandler(Msg::A, [this] {});XRegisterMsgHandler(Msg::B, [this](const std::any& data) {});}~ClassA() {XDeregister();}};struct ClassB {ClassB() {XRegisterMsgHandler(Msg::A, [this] {});XRegisterMsgHandler(Msg::B, [this](const std::any& data) {});}~ClassB() {XDeregister();}};ClassA a;ClassB b;XConnect(&a, &b);const auto& globalMsgHandler = InstMsgHandler::GetInstance()->globalMsgHandler_;const auto& communicators = InstMsgHandler::GetInstance()->communicators_;m_results.push_back(globalMsgHandler.size() == 2);m_results.push_back(globalMsgHandler.at("Msg::A").size() == 2);m_results.push_back(globalMsgHandler.at("Msg::B").size() == 2);m_results.push_back(communicators.size() == 2);m_results.push_back(communicators.at(&a).size() == 1);m_results.push_back(communicators.at(&b).size() == 1);XDisconnect(&a, &b);m_results.push_back(globalMsgHandler.size() == 2);m_results.push_back(globalMsgHandler.at("Msg::A").size() == 2);m_results.push_back(globalMsgHandler.at("Msg::B").size() == 2);m_results.push_back(communicators.size() == 2);m_results.push_back(communicators.at(&a).size() == 0);m_results.push_back(communicators.at(&b).size() == 0);QVERIFY(VarifyResult());
}int TriggerNoParamTestTempVar = 0;
void InstMsgHandlerUnitTest::ABTriggerNoParamTest()
{TriggerNoParamTestTempVar = 0;struct ClassA {ClassA() {XRegisterMsgHandler(Msg::A, [this] {TriggerNoParamTestTempVar += 1;});XRegisterMsgHandler(Msg::B, [this](const std::any& data) {});}~ClassA() {XDeregister();}void Call() {XTriggerMsg(Msg::A);}};struct ClassB {ClassB() {XRegisterMsgHandler(Msg::A, [this] {TriggerNoParamTestTempVar += 1;});XRegisterMsgHandler(Msg::B, [this](const std::any& data) {});}~ClassB() {XDeregister();}void Call() {XTriggerMsg(Msg::A);}};ClassA a;ClassB b;XConnect(&a, &b);const auto& globalMsgHandler = InstMsgHandler::GetInstance()->globalMsgHandler_;const auto& communicators = InstMsgHandler::GetInstance()->communicators_;m_results.push_back(globalMsgHandler.size() == 2);m_results.push_back(globalMsgHandler.at("Msg::A").size() == 2);m_results.push_back(globalMsgHandler.at("Msg::B").size() == 2);m_results.push_back(communicators.size() == 2);m_results.push_back(communicators.at(&a).size() == 1);m_results.push_back(communicators.at(&b).size() == 1);a.Call();m_results.push_back(TriggerNoParamTestTempVar == 1);b.Call();m_results.push_back(TriggerNoParamTestTempVar == 2);XDisconnect(&a, &b);a.Call();m_results.push_back(TriggerNoParamTestTempVar == 2);b.Call();m_results.push_back(TriggerNoParamTestTempVar == 2);QVERIFY(VarifyResult());
}int TriggerHasParamTestTempVar = 0;
void InstMsgHandlerUnitTest::ABTriggerHasParamTest()
{TriggerHasParamTestTempVar = 0;struct ClassA {ClassA() {XRegisterMsgHandler(Msg::A, [this] {});XRegisterMsgHandler(Msg::B, [this](const std::any& data) {TriggerHasParamTestTempVar = std::any_cast<int>(data);});}~ClassA() {XDeregister();}void Call() {XTriggerMsg(Msg::B, 100);}};struct ClassB {ClassB() {XRegisterMsgHandler(Msg::A, [this] {});XRegisterMsgHandler(Msg::B, [this](const std::any& data) {TriggerHasParamTestTempVar = std::any_cast<int>(data);});}~ClassB() {XDeregister();}void Call() {XTriggerMsg(Msg::B, -100);}};ClassA a;ClassB b;XConnect(&a, &b);const auto& globalMsgHandler = InstMsgHandler::GetInstance()->globalMsgHandler_;const auto& communicators = InstMsgHandler::GetInstance()->communicators_;m_results.push_back(globalMsgHandler.size() == 2);m_results.push_back(globalMsgHandler.at("Msg::A").size() == 2);m_results.push_back(globalMsgHandler.at("Msg::B").size() == 2);m_results.push_back(communicators.size() == 2);m_results.push_back(communicators.at(&a).size() == 1);m_results.push_back(communicators.at(&b).size() == 1);a.Call();m_results.push_back(TriggerHasParamTestTempVar == 100);b.Call();m_results.push_back(TriggerHasParamTestTempVar == -100);QVERIFY(VarifyResult());
}void InstMsgHandlerUnitTest::XConnectBaseTest()
{struct ClassA {ClassA() {XRegisterMsgHandler(Msg::A, [this] {});XRegisterMsgHandler(Msg::B, [this](const std::any& data) {});}~ClassA() {XDeregister();}};struct ClassB : ClassA {ClassB() {XConnect(this);}~ClassB() {XDeregister();}};ClassB b;const auto& globalMsgHandler = InstMsgHandler::GetInstance()->globalMsgHandler_;const auto& communicators = InstMsgHandler::GetInstance()->communicators_;m_results.push_back(globalMsgHandler.size() == 2);m_results.push_back(globalMsgHandler.at("Msg::A").size() == 1);m_results.push_back(globalMsgHandler.at("Msg::B").size() == 1);m_results.push_back(communicators.size() == 1);m_results.push_back(communicators.at(&b).size() == 1);
}int BaseTriggerNoParamTestTempVar = 0;
void InstMsgHandlerUnitTest::BaseTriggerNoParamTest()
{BaseTriggerNoParamTestTempVar = 0;struct ClassA {ClassA() {XRegisterMsgHandler(Msg::A, [this] {BaseTriggerNoParamTestTempVar += 1;});XRegisterMsgHandler(Msg::B, [this](const std::any& data) {});}~ClassA() {XDeregister();}void CallBase() {XTriggerMsg(Msg::A);}};struct ClassB : ClassA {ClassB() {XConnect(this);}~ClassB() {XDeregister();}void CallDriver() {XTriggerMsg(Msg::A);}};ClassB b;const auto& globalMsgHandler = InstMsgHandler::GetInstance()->globalMsgHandler_;const auto& communicators = InstMsgHandler::GetInstance()->communicators_;m_results.push_back(globalMsgHandler.size() == 2);m_results.push_back(globalMsgHandler.at("Msg::A").size() == 1);m_results.push_back(globalMsgHandler.at("Msg::B").size() == 1);m_results.push_back(communicators.size() == 1);m_results.push_back(communicators.at(&b).size() == 1);b.CallBase();m_results.push_back(BaseTriggerNoParamTestTempVar == 1);b.CallDriver();m_results.push_back(BaseTriggerNoParamTestTempVar == 2);QVERIFY(VarifyResult());
}int BaseTriggerHasParamTestTempVar = 0;
void InstMsgHandlerUnitTest::BaseTriggerHasParamTest()
{BaseTriggerHasParamTestTempVar = 0;struct ClassA {ClassA() {XRegisterMsgHandler(Msg::A, [this] {});XRegisterMsgHandler(Msg::B, [this](const std::any& data) {BaseTriggerHasParamTestTempVar = std::any_cast<int>(data);});}~ClassA() {XDeregister();}void CallBase() {XTriggerMsg(Msg::B, 100);}};struct ClassB : ClassA {ClassB() {XConnect(this);}~ClassB() {XDeregister();}void CallDriver() {XTriggerMsg(Msg::B, -100);}};ClassB b;const auto& globalMsgHandler = InstMsgHandler::GetInstance()->globalMsgHandler_;const auto& communicators = InstMsgHandler::GetInstance()->communicators_;m_results.push_back(globalMsgHandler.size() == 2);m_results.push_back(globalMsgHandler.at("Msg::A").size() == 1);m_results.push_back(globalMsgHandler.at("Msg::B").size() == 1);m_results.push_back(communicators.size() == 1);m_results.push_back(communicators.at(&b).size() == 1);b.CallBase();m_results.push_back(BaseTriggerHasParamTestTempVar == 100);b.CallDriver();m_results.push_back(BaseTriggerHasParamTestTempVar == -100);QVERIFY(VarifyResult());
}void InstMsgHandlerUnitTest::MemoryLeakTest()
{struct ClassA {ClassA() {XRegisterMsgHandler(Msg::A, [this] {});XRegisterMsgHandler(Msg::B, [this](const std::any& data) {});}~ClassA() {XDeregister();}int a = 0;};struct ClassB {ClassB() {XRegisterMsgHandler(Msg::A, [this] {});XRegisterMsgHandler(Msg::B, [this](const std::any& data) {});}~ClassB() {XDeregister();}int b = 0;};auto beginMemory = GetCurMemoryKB();{std::vector<ClassA*> veca;std::vector<ClassB*> vecb;for (int i = 0; i < 10000; ++i) {ClassA* a = new ClassA;ClassB* b = new ClassB;XConnect(a, b);veca.push_back(a);vecb.push_back(b);}const auto& globalMsgHandler = InstMsgHandler::GetInstance()->globalMsgHandler_;const auto& communicators = InstMsgHandler::GetInstance()->communicators_;m_results.push_back(globalMsgHandler.size() == 2);m_results.push_back(globalMsgHandler.at("Msg::A").size() == 20000);m_results.push_back(globalMsgHandler.at("Msg::B").size() == 20000);m_results.push_back(communicators.size() == 20000);for (auto& communicator : communicators) {QVERIFY(communicator.second.size() == 1);}for (auto& v : veca) {delete v;}for (auto& v : vecb) {delete v;}veca.clear();vecb.clear();m_results.push_back(globalMsgHandler.size() == 2);m_results.push_back(globalMsgHandler.at("Msg::A").size() == 0);m_results.push_back(globalMsgHandler.at("Msg::B").size() == 0);m_results.push_back(communicators.size() == 0);}auto endMemory = GetCurMemoryKB();QVERIFY(endMemory - beginMemory < 30);
}void InstMsgHandlerUnitTest::BaseMemoryLeakTest()
{struct ClassA {ClassA() {XRegisterMsgHandler(Msg::A, [this] {});XRegisterMsgHandler(Msg::B, [this](const std::any& data) {});}~ClassA() {XDeregister();}int a = 0;};struct ClassB : ClassA {ClassB() {XRegisterMsgHandler(Msg::A, [this] {});XRegisterMsgHandler(Msg::B, [this](const std::any& data) {});XConnect(this);}~ClassB() {XDeregister();}int b = 0;};auto beginMemory = GetCurMemoryKB();{std::vector<ClassB*> vecb;for (int i = 0; i < 10000; ++i) {vecb.push_back(new ClassB);}for (auto& v : vecb) {delete v;}vecb.clear();}auto endMemory = GetCurMemoryKB();QVERIFY(endMemory - beginMemory < 30);
}bool InstMsgHandlerUnitTest::VarifyResult()
{bool result = true;for (auto& rlt : m_results) {if (!rlt) {result = false;break;}}return result;
}void InstMsgHandlerUnitTest::initTestCase()
{
}void InstMsgHandlerUnitTest::cleanupTestCase()
{
}void InstMsgHandlerUnitTest::init()
{m_results.clear();InstMsgHandler::GetInstance()->globalMsgHandler_.clear();InstMsgHandler::GetInstance()->communicators_.clear();
}void InstMsgHandlerUnitTest::cleanup()
{
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/75721.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

AI Agent设计模式一:Chain

概念 &#xff1a;线性任务流设计 ✅ 优点&#xff1a;逻辑清晰易调试&#xff0c;适合线性处理流程❌ 缺点&#xff1a;缺乏动态分支能力 from typing import TypedDictfrom langgraph.graph import StateGraph, END# 定义后续用到的一些变量 class CustomState(TypedDict):p…

Git三剑客:工作区、暂存区、版本库深度解析

一、引言&#xff1a;为什么需要理解Git的核心区域&#xff1f; 作为开发者&#xff0c;Git是日常必备的版本控制工具。但你是否曾因以下问题感到困惑&#xff1f; 修改了文件&#xff0c;但 git status 显示一片混乱&#xff1f; git add 和 git commit 到底做了什么&#x…

Python数据类型-list

列表(List)是Python中最常用的数据类型之一&#xff0c;它是一个有序、可变的元素集合。 1. 列表基础 创建列表 empty_list [] # 空列表 numbers [1, 2, 3, 4, 5] # 数字列表 fruits [apple, banana, orange] # 字符串列表 mixed [1, hello, 3.14, True] # 混合类型…

Keepalive+LVS+Nginx+NFS高可用项目

项目架构 分析 主机规划 主机系统安装应用网络IPclientredhat 9.5无NAT172.25.250.115/24lvs-masterrocky 9.5ipvsadm&#xff0c;keepalivedNAT172.25.250.116/24 VIP 172.25.250.100/32lvs-backuprocky 9.5ipvsadm&#xff0c;keepalivedNAT172.25.250.117/24 VIP 172.25.2…

【视觉与语言模型参数解耦】为什么?方案?

一些无编码器的MLLMs统一架构如Fuyu&#xff0c;直接在LLM内处理原始像素&#xff0c;消除了对外部视觉模型的依赖。但是面临视觉与语言模态冲突的挑战&#xff0c;导致训练不稳定和灾难性遗忘等问题。解决方案则是通过参数解耦方法解决模态冲突。 在多模态大语言模型&#xf…

AI比人脑更强,因为被植入思维模型【43】蝴蝶效应思维模型

giszz的理解&#xff1a;蝴蝶效应我们都熟知&#xff0c;就是说一个微小的变化&#xff0c;能带动整个系统甚至系统的空间和时间的远端&#xff0c;产生巨大的链式反应。我学习后的启迪&#xff0c;简单的说&#xff0c;就是不要忽视任何微小的问题&#xff0c;更多时候&#x…

AI 数理逻辑基础之统计学基本原理(上)

目录 文章目录 目录统计学统计学基本概念描述性统计数据可视化图表工具 汇总统计统计数据的分布情况&#xff1a;中位数、众数、平均值统计数据的离散程度&#xff1a;极差、方差、标准差、离散系数 相关分析Pearson 线性关系相关系数Spearman 单调关系相关系数 回归分析回归模…

无招回归阿里

这两天&#xff0c;无招回归阿里的新闻被刷屏了。无招创业成立的两氢一氧公司无招的股份也被阿里收购&#xff0c;无招以这种姿态回归阿里&#xff0c;并且出任钉钉的 CEO。有人说&#xff0c;这是对 5 年前“云钉一体”战略的纠偏。现在确实从云优先到 AI 优先&#xff0c;但云…

算法题(114):矩阵距离

审题&#xff1a; 本题需要我们找出所有0距离最近的1的曼哈顿距离 思路&#xff1a; 方法一&#xff1a;多源bfs 分析曼哈顿距离&#xff1a; 求法1&#xff1a;公式法&#xff0c;带入题目公式&#xff0c;利用|x1-x2||y1-y2|求出 求法2&#xff1a;曼哈顿距离就是最短距离 本…

LLM 性能优化有哪些手段?

LLM(大语言模型)性能优化是一个多维度、多层次的系统工程,涉及从提示工程到模型微调,从推理加速到系统架构优化等多个方面。以下是当前主流的优化手段及其技术细节: 一、提示工程(Prompt Engineering) 提示工程是优化LLM性能最直接、成本最低的方法,适用于快速原型开发…

群体智能避障革命:RVO算法在Unity中的深度实践与优化

引言&#xff1a;游戏群体移动的挑战与进化 在《全面战争》中万人战场恢弘列阵&#xff0c;在《刺客信条》闹市里人群自然涌动&#xff0c;这些令人惊叹的场景背后&#xff0c;都离不开一个关键技术——群体动态避障。传统路径规划算法&#xff08;如A*&#xff09;虽能解决单…

I.MX6ULL 交叉编译环境配置与使用

一、什么是交叉编译 我们一般开发程序在自己的电脑上开发&#xff0c;运行的时候将程序烧录到板子运行。但我们的开发平台是X86架构&#xff0c;而I.MX6ULL是ARM架构&#xff0c;所以需要一个在 X86 架构的 PC 上运行&#xff0c;可以编译 ARM 架构代码的 GCC 编译器&#xff0…

Harmony OS“一多” 详解:基于窗口变化的断点自适应实现

一、一多开发核心概念&#xff08;18N模式&#xff09; 目标&#xff1a;一次开发多端部署 解决的问题&#xff1a; 1、界面级一多&#xff1a;适配不同屏幕尺寸 2、功能级一多&#xff1a;设备功能兼容性处理(CanIUser) 3、工…

SpringMvc获取请求数据

基本参数 RequestMapping("save5") ResponseBody public User save5(String name, int age) {User user new User();user.setName(name);user.setAge(age);return user; } 在url中将name与age进行编写&#xff0c;通过框架可以提取url中的name与age&#xff0c;这…

大模型持续学习方案解析:灾难性遗忘的工业级解决方案

引言 随着大型语言模型&#xff08;LLMs&#xff09;如 GPT 系列、BERT 等在自然语言处理领域取得突破性进展&#xff0c;它们强大的理解和生成能力已经渗透到各行各业。然而&#xff0c;这些模型通常是在海量静态数据集上进行一次性预训练的。现实世界是动态变化的&#xff0…

推荐系统(二十二):基于MaskNet和WideDeep的商品推荐CTR模型实现

在上一篇文章《推荐系统&#xff08;二十一&#xff09;&#xff1a;基于MaskNet的商品推荐CTR模型实现》中&#xff0c;笔者基于 MaskNet 构建了一个简单的模型。笔者所经历的工业级实践证明&#xff0c;将 MaskNet 和 Wide&Deep 结合应用&#xff0c;可以取得不错的效果&…

【爬虫案例】采集 Instagram 平台数据几种方式(python脚本可直接运行)

更多内容请见: 爬虫和逆向教程-专栏介绍和目录 文章目录 一、概述1.1 Instagram基础信息1.2 Instagram平台架构核心技术栈1.3 采集提示1.4 几种采集方案对比二、四种采集方案分析三、写爬虫采集Instagram案例3.1 采集作品信息并下载视频或图片(无需登录)3.2 explore接口的采…

OFP--2018

文章目录 AbstractIntroductionRelated Work2D object detection3D object detection from LiDAR3D object detection from imagesIntegral images 3D Object Detection ArchitectureFeature extractionOrthographic feature transformFast average pooling with integral imag…

LINUX 4 tar -zcvf -jcvf -Jcvf -tf -uf

cp -r mv: 1.移动文件到目录 2.文件改名 3.目录改名 s 上面是打包 下面是打包并压缩

linux signal up/down/down_interruptiable\down_uninterruptiable使用

在Linux内核中&#xff0c;down, down_interruptible, down_killable, 和 up 是用于操作信号量&#xff08;semap hores&#xff09;的函数&#xff0c;它们用于进程同步和互斥。以下是对这些函数的简要说明。 1&#xff0c;down(&sem): 这个函数用于获取信号量。如果信号…