重构共享内存字符串管理,添加 shm_string 类以支持 RPC 浅拷贝,更新 rpc_manager 以注册析构器

This commit is contained in:
daiqingshuang
2025-08-27 11:46:30 +08:00
parent a77ef342cb
commit a6d5b3fe32
9 changed files with 265 additions and 73 deletions

View File

@@ -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());
}
};

View File

@@ -6,40 +6,6 @@
#include "shm_manager.h"
#include "shm_audio_buffer.h" // AudioBuffer 具体实现
#include <utility> // 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<shm_string>(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<shm_string>(id.c_str());
return ptr;
}
// 按名称销毁字符串
void shm_manager::destroy_str(const std::string& id) { str_shm_block->destroy<shm_string>(id.c_str()); }
// 按指针销毁字符串
void shm_manager::destroy_str(shm_string* ptr) { str_shm_block->destroy_ptr(ptr); }
// ---------------------------------------------------------------------------
// 共享内存整体分配

View File

@@ -116,21 +116,10 @@ public:
template<typename T>
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:
/* --------- 内部实现 --------- */

View File

@@ -0,0 +1,148 @@
#include "shm_string.h"
#include <boost/uuid/random_generator.hpp>
#include <boost/uuid/uuid_io.hpp>
#include <algorithm>
#include <stdexcept>
#include <utility>
#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<shm_string_row>(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<shm_string_row>(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<typename Func>
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<shm_string_row>(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<boost::uuids::uuid>& 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<shm_string_row>(id_str.c_str());
}
}
}
catch (...) {
// 批量操作的异常处理
}
}
}

View File

@@ -0,0 +1,76 @@
#pragma once
#include <boost/uuid/uuid.hpp>
#include <string>
#include <string_view>
#include "shm_manager.h"
#include "rpc/common.h"
using char_allocator = allocator_t<char>;
using shm_string_row = bc::basic_string<char, std::char_traits<char>, 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<typename Func>
auto with_shm_string(Func&& func) const -> decltype(func(nullptr));
boost::uuids::uuid uuid_;
};
// 工具函数
namespace shm_string_utils {
// 批量操作工具(减少锁竞争)
void batch_destroy(const std::vector<boost::uuids::uuid>& uuids);
}

View File

@@ -24,9 +24,6 @@ using lock_free_queue = boost::lockfree::spsc_queue<audio_block, boost::lockfree
template<typename T>
using allocator_t = bi::allocator<T, bi::managed_shared_memory::segment_manager>;
using char_allocator = allocator_t<char>;
using shm_string = bc::basic_string<char, std::char_traits<char>, char_allocator>;
template<typename Msg>
struct msg_id_t{};

View File

@@ -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<uint32_t>(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<uint32_t>(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<uint32_t>(in_msg.message_id)); }
if (const auto dit = destructors_.find(in_msg.message_id); dit != destructors_.end()) {
dit->second(in_msg.data.data());
}
}

View File

@@ -39,6 +39,7 @@ namespace bc = boost::container;
// --- 类型别名与前向声明 (Type Aliases & FWD Decls) --------------------------
using rpc_callback = std::function<void(const void*)>; // 统一 RPC 回调签名
using rpc_destructor = std::function<void(const void*)>; // 统一析构回调签名
// --- 数据结构定义 (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:
// 储存 <message_type, 处理回调>
std::unordered_map<rpc::message_type, rpc_callback> handlers_;
// 存储 <message_type, 析构回调>
std::unordered_map<rpc::message_type, rpc_destructor> destructors_;
};
// --- 模板工具 & 宏 (Template Helpers & Macros) -------------------------------
@@ -120,11 +125,22 @@ private:
template<typename Msg>
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<Msg>().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<Msg>().destroy(); }) {
auto real_destructor = [](const void* payload) {
((Msg*)payload)->destroy();
};
rpc_message_handler::get_instance().register_rpc_destructor(in_type, real_destructor);
}
}
};

View File

@@ -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;
};
}