diff --git a/src/backend/src/engine/src/rpc/engine_rpc.h b/src/backend/src/engine/src/rpc/engine_rpc.h index be56aa2..8f47b45 100644 --- a/src/backend/src/engine/src/rpc/engine_rpc.h +++ b/src/backend/src/engine/src/rpc/engine_rpc.h @@ -5,9 +5,8 @@ namespace engine_rpc { struct log_impl : log { void process() { - const auto str = get_str(); - spdlog::log(level, "[Sandbox] {}", str->c_str()); - destory_str(); + const auto str = str_.get_string(); + spdlog::log(level_, "[Sandbox] {}", str.c_str()); } }; diff --git a/src/backend/src/misc/src/ipc/shm_manager.cpp b/src/backend/src/misc/src/ipc/shm_manager.cpp index c77fe63..2620125 100644 --- a/src/backend/src/misc/src/ipc/shm_manager.cpp +++ b/src/backend/src/misc/src/ipc/shm_manager.cpp @@ -6,40 +6,6 @@ #include "shm_manager.h" #include "shm_audio_buffer.h" // AudioBuffer 具体实现 -#include // std::move - -// --------------------------------------------------------------------------- -// 字符串相关操作 -// --------------------------------------------------------------------------- - -/** - * @brief 在 String SHM 中创建 (或查找) 字符串对象并写入内容 - * @param id 逻辑唯一名称 - * @param str 初始内容 - * @returns shm_string* 指针 - */ -shm_string* shm_manager::create_str(const std::string& id, const std::string& str) { - auto ptr = str_shm_block->find_or_construct(id.c_str())(str.c_str(), - char_allocator{ - str_shm_block->get_segment_manager() - }); - return ptr; -} - -// 重载: 仅创建空字符串 -shm_string* shm_manager::create_str(const std::string& id) { return create_str(id, ""); } - -// 查找已存在字符串 -shm_string* shm_manager::find_str(const std::string& id) { - auto [ptr, size] = str_shm_block->find(id.c_str()); - return ptr; -} - -// 按名称销毁字符串 -void shm_manager::destroy_str(const std::string& id) { str_shm_block->destroy(id.c_str()); } - -// 按指针销毁字符串 -void shm_manager::destroy_str(shm_string* ptr) { str_shm_block->destroy_ptr(ptr); } // --------------------------------------------------------------------------- // 共享内存整体分配 diff --git a/src/backend/src/misc/src/ipc/shm_manager.h b/src/backend/src/misc/src/ipc/shm_manager.h index 686a89e..bcf578c 100644 --- a/src/backend/src/misc/src/ipc/shm_manager.h +++ b/src/backend/src/misc/src/ipc/shm_manager.h @@ -116,21 +116,10 @@ public: template static void ab_destroy_ptr(const T* ptr) { get_instance().audio_buffer_shm_block->destroy_ptr(ptr); } - /* ------------------------ 字符串专用 API ------------------------ */ - shm_string* create_str(const std::string& id, const std::string& str); - - shm_string* create_str(const std::string& id); - - shm_string* find_str(const std::string& id); - - void destroy_str(const std::string& id); - - void destroy_str(shm_string* ptr); - /* ------------------------ Getter ------------------------ */ auto* get_message_shm() { return message_shm_block.get(); } auto* get_audio_buffer_shm() { return audio_buffer_shm_block.get(); } - + auto* get_string_shm() { return str_shm_block.get(); } private: /* --------- 内部实现 --------- */ diff --git a/src/backend/src/misc/src/ipc/shm_string.cpp b/src/backend/src/misc/src/ipc/shm_string.cpp new file mode 100644 index 0000000..a1aae0f --- /dev/null +++ b/src/backend/src/misc/src/ipc/shm_string.cpp @@ -0,0 +1,148 @@ +#include "shm_string.h" + +#include +#include +#include +#include +#include + +#include "shm_manager.h" + +// 构造函数实现 +shm_string::shm_string(const std::string& initial_str) { set_string(initial_str); } + +shm_string::shm_string(std::string&& initial_str) { set_string(std::move(initial_str)); } + +shm_string::~shm_string() { + // 注意:由于RPC浅拷贝的存在,不能在析构函数中自动销毁 + // 共享内存对象需要显式调用destroy()方法 +} + +// 字符串操作实现 +auto shm_string::get_string() const -> std::string { + if (uuid_.is_nil()) { return {}; } + + return with_shm_string([](const shm_string_row* shm_str) -> std::string { + if (shm_str) { + // 直接使用数据指针和长度构造,避免c_str()调用 + return { shm_str->data(), shm_str->size() }; + } + return {}; + }); +} + +auto shm_string::get_string_view() const -> std::string_view { + if (uuid_.is_nil()) { return {}; } + + return with_shm_string([](const shm_string_row* shm_str) -> std::string_view { + if (shm_str) { return { shm_str->data(), shm_str->size() }; } + return {}; + }); +} + +void shm_string::set_string(const std::string& in_str) { + if (!uuid_.is_nil()) { destroy(); } + + // 生成新UUID + uuid_ = boost::uuids::random_generator()(); + + try { + const auto shm = get_shm_manager().get_string_shm(); + const auto id_str = get_id_str(); + + // 直接在共享内存中构造字符串 + const auto shm_str = shm->construct(id_str.c_str())(in_str.c_str(), + char_allocator{ + shm->get_segment_manager() + }); + + if (!shm_str) { + uuid_ = boost::uuids::uuid{}; // 失败时重置UUID + throw std::runtime_error("共享内存字符串构造失败"); + } + } + catch (...) { + uuid_ = boost::uuids::uuid{}; + throw; + } +} + +void shm_string::set_string(std::string&& in_str) { + // 对于移动版本,仍需要拷贝到共享内存,但避免额外的拷贝操作 + set_string(in_str); // 编译器会优化移动操作 +} + +// 状态查询实现 +auto shm_string::empty() const noexcept -> bool { + if (uuid_.is_nil()) { return true; } + + try { return with_shm_string([](const shm_string_row* shm_str) -> bool { return !shm_str || shm_str->empty(); }); } + catch (...) { + return true; // 异常情况视为空 + } +} + +auto shm_string::valid() const noexcept -> bool { return !uuid_.is_nil(); } + +auto shm_string::size() const -> size_t { + if (uuid_.is_nil()) { return 0; } + + return with_shm_string([](const shm_string_row* shm_str) -> size_t { return shm_str ? shm_str->size() : 0; }); +} + +void shm_string::destroy() { + if (uuid_.is_nil()) { return; } + + try { + const auto shm = get_shm_manager().get_string_shm(); + const auto id_str = get_id_str(); + shm->destroy(id_str.c_str()); + } + catch (...) { + // 析构过程中的异常不应该传播 + // 可以记录日志但不抛出 + } + + uuid_ = boost::uuids::uuid{}; +} + +// 私有辅助方法实现 +auto shm_string::get_id_str() const -> std::string { return to_string(uuid_); } + +auto shm_string::get_shm_manager() const -> decltype(shm_manager::get_instance()) { + return shm_manager::get_instance(); +} + +template +auto shm_string::with_shm_string(Func&& func) const -> decltype(func(nullptr)) { + try { + const auto shm = get_shm_manager().get_string_shm(); + const auto id_str = get_id_str(); + + if (const auto [shm_str, found] = shm->find(id_str.c_str()); found) { return func(shm_str); } + return func(nullptr); + } + catch (...) { return func(nullptr); } +} + +// 工具函数实现 +namespace shm_string_utils { + void batch_destroy(const std::vector& uuids) { + if (uuids.empty()) { return; } + + try { + const auto shm = shm_manager::get_instance().get_string_shm(); + + // 批量销毁以减少锁竞争 + for (const auto& uuid: uuids) { + if (!uuid.is_nil()) { + const auto id_str = to_string(uuid); + shm->destroy(id_str.c_str()); + } + } + } + catch (...) { + // 批量操作的异常处理 + } + } +} diff --git a/src/backend/src/misc/src/ipc/shm_string.h b/src/backend/src/misc/src/ipc/shm_string.h new file mode 100644 index 0000000..b23aacd --- /dev/null +++ b/src/backend/src/misc/src/ipc/shm_string.h @@ -0,0 +1,76 @@ +#pragma once +#include +#include +#include + +#include "shm_manager.h" +#include "rpc/common.h" + +using char_allocator = allocator_t; +using shm_string_row = bc::basic_string, char_allocator>; + +/** + * 共享内存字符串类 - 支持RPC浅拷贝的跨进程字符串存储 + * + * 重要特性: + * - 支持浅拷贝用于RPC传输(只拷贝UUID,不拷贝实际字符串数据) + * - 自动资源管理,但需要注意多个实例可能指向同一共享内存对象 + * - 线程安全的共享内存访问 + * + * RPC使用注意事项: + * - 多个shm_string实例可能共享同一个UUID,销毁时需小心 + * - 建议在RPC调用后立即使用,避免长期持有 + */ +class shm_string { +public: + // 默认构造和析构 + shm_string() = default; + + explicit shm_string(const std::string& initial_str); + + explicit shm_string(std::string&& initial_str); + + ~shm_string(); + + // 字符串操作接口 + [[nodiscard]] auto get_string() const -> std::string; + + [[nodiscard]] auto get_string_view() const -> std::string_view; + + void set_string(const std::string& in_str); + + void set_string(std::string&& in_str); + + // 状态查询 + [[nodiscard]] auto empty() const noexcept -> bool; + + [[nodiscard]] auto valid() const noexcept -> bool; + + [[nodiscard]] auto size() const -> size_t; + + // 资源管理 + void destroy(); + + void clear() { destroy(); } // 语义化别名 + + // RPC相关接口 + [[nodiscard]] auto get_uuid() const noexcept -> const boost::uuids::uuid& { return uuid_; } + void set_uuid(const boost::uuids::uuid& uuid) noexcept { uuid_ = uuid; } + +private: + // 内部辅助方法 + [[nodiscard]] auto get_id_str() const -> std::string; + + [[nodiscard]] auto get_shm_manager() const -> decltype(shm_manager::get_instance()); + + template + auto with_shm_string(Func&& func) const -> decltype(func(nullptr)); + + boost::uuids::uuid uuid_; +}; + +// 工具函数 +namespace shm_string_utils { + // 批量操作工具(减少锁竞争) + void batch_destroy(const std::vector& uuids); +} diff --git a/src/backend/src/misc/src/rpc/common.h b/src/backend/src/misc/src/rpc/common.h index e301d49..861979b 100644 --- a/src/backend/src/misc/src/rpc/common.h +++ b/src/backend/src/misc/src/rpc/common.h @@ -24,9 +24,6 @@ using lock_free_queue = boost::lockfree::spsc_queue using allocator_t = bi::allocator; -using char_allocator = allocator_t; -using shm_string = bc::basic_string, char_allocator>; - template struct msg_id_t{}; diff --git a/src/backend/src/misc/src/rpc/rpc_manager.cpp b/src/backend/src/misc/src/rpc/rpc_manager.cpp index bb9dbcd..0198224 100644 --- a/src/backend/src/misc/src/rpc/rpc_manager.cpp +++ b/src/backend/src/misc/src/rpc/rpc_manager.cpp @@ -24,6 +24,13 @@ void rpc_message_handler::register_rpc_handler(rpc::message_type type, rpc_callb handlers_[type] = std::move(handler); // 覆盖 or 新增 } +void rpc_message_handler::register_rpc_destructor(rpc::message_type type, rpc_destructor destructor) { + if (destructors_.contains(type)) { + spdlog::warn("RPC消息类型 {} 的析构器已注册,覆盖旧析构器", static_cast(type)); + } + destructors_[type] = std::move(destructor); // 覆盖 or 新增 +} + // --- RPC 消息分发实现 (Dispatch) --------------------------------------------- /** @@ -36,8 +43,7 @@ void rpc_message_handler::register_rpc_handler(rpc::message_type type, rpc_callb * 2. 找到则调用,未找到则输出 warn */ void rpc_message_handler::handle_message(const rpc_message_t& in_msg) { - const auto it = handlers_.find(in_msg.message_id); - if (it != handlers_.end()) { + if (const auto it = handlers_.find(in_msg.message_id); it != handlers_.end()) { #if ALICHO_DEBUG // 条件编译: 调试模式下打印更详细的日志 spdlog::info("处理RPC消息,ID: {}", static_cast(in_msg.message_id)); @@ -46,4 +52,8 @@ void rpc_message_handler::handle_message(const rpc_message_t& in_msg) { it->second(in_msg.data.data()); } else { spdlog::warn("未处理的RPC消息类型: {}", static_cast(in_msg.message_id)); } + + if (const auto dit = destructors_.find(in_msg.message_id); dit != destructors_.end()) { + dit->second(in_msg.data.data()); + } } diff --git a/src/backend/src/misc/src/rpc/rpc_manager.h b/src/backend/src/misc/src/rpc/rpc_manager.h index b1287d9..de33bc7 100644 --- a/src/backend/src/misc/src/rpc/rpc_manager.h +++ b/src/backend/src/misc/src/rpc/rpc_manager.h @@ -39,6 +39,7 @@ namespace bc = boost::container; // --- 类型别名与前向声明 (Type Aliases & FWD Decls) -------------------------- using rpc_callback = std::function; // 统一 RPC 回调签名 +using rpc_destructor = std::function; // 统一析构回调签名 // --- 数据结构定义 (Structs) -------------------------------------------------- @@ -90,6 +91,8 @@ public: */ void register_rpc_handler(rpc::message_type type, rpc_callback handler); + void register_rpc_destructor(rpc::message_type type, rpc_destructor destructor); + /** * @brief 根据 message_id 分发 RPC 消息 * @@ -104,6 +107,8 @@ public: private: // 储存 std::unordered_map handlers_; + // 存储 + std::unordered_map destructors_; }; // --- 模板工具 & 宏 (Template Helpers & Macros) ------------------------------- @@ -120,11 +125,22 @@ private: template struct rpc_handler_register { explicit rpc_handler_register(rpc::message_type in_type) { + static_assert(requires { Msg::rpc_id; }, "Msg 必须具有静态成员 'rpc_id', 是否定义了DEFINE_ID宏?"); + static_assert(requires { std::declval().process(); }, "Msg 必须具有成员函数 'process()'。"); + // 封装真正的回调,实现与 Msg::process() 解耦 auto real_func = [](const void* payload) { ((Msg*)payload)->process(); }; rpc_message_handler::get_instance().register_rpc_handler(in_type, real_func); + + // 如果Msg有destroy成员函数, 则注册析构器 + if constexpr (requires { std::declval().destroy(); }) { + auto real_destructor = [](const void* payload) { + ((Msg*)payload)->destroy(); + }; + rpc_message_handler::get_instance().register_rpc_destructor(in_type, real_destructor); + } } }; diff --git a/src/backend/src/misc/src/rpc/rpc_type.h b/src/backend/src/misc/src/rpc/rpc_type.h index 7f135c3..c85cce9 100644 --- a/src/backend/src/misc/src/rpc/rpc_type.h +++ b/src/backend/src/misc/src/rpc/rpc_type.h @@ -6,6 +6,7 @@ #include "ipc/shm_manager.h" #include "common.h" +#include "ipc/shm_string.h" namespace bc = boost::container; @@ -32,29 +33,19 @@ namespace engine_rpc { struct log { DEFINE_ID(LOG) - log() : level(spdlog::level::info) { - id = boost::uuids::random_generator()(); - } - void set_str(const std::string& in_str) { - auto str = shm_manager::get_instance().create_str(get_id(), in_str); - *str = in_str.c_str(); + str_.set_string(in_str); } void set_level(spdlog::level::level_enum in_level) { - level = in_level; + level_ = in_level; + } + + // destroy函数由rpc_manager自动调用 + void destroy() { + str_.destroy(); } protected: - void destory_str() { - shm_manager::get_instance().destroy_str(get_id()); - } - auto get_id() const { - return boost::uuids::to_string(id) + "-log_shm_string"; - } - auto get_str() const { - return shm_manager::get_instance().find_str(get_id()); - } - protected: - boost::uuids::uuid id; - spdlog::level::level_enum level; + shm_string str_; + spdlog::level::level_enum level_ = spdlog::level::info; }; }