重构共享内存字符串管理,添加 shm_string 类以支持 RPC 浅拷贝,更新 rpc_manager 以注册析构器
This commit is contained in:
@@ -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());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -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); }
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// 共享内存整体分配
|
||||
|
||||
@@ -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:
|
||||
/* --------- 内部实现 --------- */
|
||||
|
||||
|
||||
148
src/backend/src/misc/src/ipc/shm_string.cpp
Normal file
148
src/backend/src/misc/src/ipc/shm_string.cpp
Normal 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 (...) {
|
||||
// 批量操作的异常处理
|
||||
}
|
||||
}
|
||||
}
|
||||
76
src/backend/src/misc/src/ipc/shm_string.h
Normal file
76
src/backend/src/misc/src/ipc/shm_string.h
Normal 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);
|
||||
}
|
||||
@@ -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{};
|
||||
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user