Files
Inbox/系统基座文件/2/2.5/2.5.4 零拷贝数据容器规范 (Zero-Copy Data Container Specification).md

177 lines
6.1 KiB
Markdown
Raw Permalink Normal View History

2025-12-11 07:24:36 +08:00
---
tags: []
date created: 星期一, 十一月 24日 2025, 11:19:42 晚上
date modified: 星期一, 十一月 24日 2025, 11:20:43 晚上
---
# 2.5.4 零拷贝数据容器规范 (Zero-Copy Data Container Specification)
**基线核心宗旨****“RAII for Ownership, Header for Context (RAII 管资产Header 管上下文)”**。
容器必须是 **Movable-Only (仅可移动)** 的,严禁拷贝。它利用 C++ 类型系统强制执行所有权的单一性,并通过标准化的 Header 确保全链路的可观测性。
-----
## 1\. 核心设计契约 (Design Contracts)
1. **仅移动语义 (Move-Only Semantics)**
- `DataPacket<T>` 的拷贝构造函数和拷贝赋值操作符必须被 **显式删除 (`= delete`)**
- **理由**:防止开发者无意中触发深拷贝,破坏零拷贝原则;防止多个对象持有同一块物理内存的所有权,导致 Double Free。
2. **统一元数据 (Unified Metadata)**
- 所有流转的数据包,无论其负载是原始波形还是航迹,都必须携带相同的 Header 结构。
- **理由**:使得中间件(如调度器、监控探针)可以在不解析 Payload 的情况下读取 `TraceID``Timestamp`
3. **自动回收 (Self-Reclamation)**
- 容器析构时,必须自动触发 Payload 的资源释放(归还内存池或释放堆内存)。
- **理由**:消除内存泄漏风险,简化模块内的错误处理逻辑(异常安全)。
-----
## 2\. 通用容器定义 (Generic Definition)
```cpp
/**
* @brief 通用零拷贝数据容器
* @tparam PayloadType 负载类型 (必须支持移动语义)
*/
template <typename PayloadType>
struct DataPacket {
// --- 1. 标准化头部 (Fixed Header) ---
struct Header {
// 全链路追踪 ID (从 TraceContext 继承)
uint64_t trace_id;
// 数据生成时间戳 (UTC Microseconds, 总控授时)
uint64_t timestamp_us;
// 流水线序列号 (用于检测内部丢包/乱序)
uint64_t sequence_id;
// 源模块标识 (用于调试拓扑)
uint32_t source_module_id;
// 标志位 (e.g., END_OF_STREAM, CONFIG_UPDATE_BARRIER)
uint32_t flags;
} header;
// --- 2. 业务负载 (Flexible Payload) ---
PayloadType payload;
// --- 3. 构造与移动语义 ---
// 默认构造
DataPacket() = default;
// 显式移动构造
DataPacket(DataPacket&& other) noexcept
: header(other.header), payload(std::move(other.payload)) {}
// 显式移动赋值
DataPacket& operator=(DataPacket&& other) noexcept {
if (this != &other) {
header = other.header;
payload = std::move(other.payload);
}
return *this;
}
// 严禁拷贝 !!!
DataPacket(const DataPacket&) = delete;
DataPacket& operator=(const DataPacket&) = delete;
};
```
-----
## 3\. 核心特化与所有权管理 (Specializations & Ownership)
根据 **2.5.1** 定义的业务对象,我们需要针对两类不同性质的数据定义具体的容器行为。
### 3.1 原始回波数据包 (`RawDataPacket`)
- **场景**`DataReceiver` -\> `SignalProcessor`。数据量极大MB 级),必须使用页锁定内存池。
- **Payload 类型**`std::unique_ptr<DataObject, MemoryPoolDeleter>`
- **所有权逻辑**
- `RawDataPacket` 持有 `unique_ptr`
- 当 Packet 在队列中移动时,`unique_ptr` 随之移动。
- 当 Packet 在消费端(`SignalProcessor`)析构时,`MemoryPoolDeleter` 被调用,将底层的 `void*` 归还给 `PinnedMemoryPool`
<!-- end list -->
```cpp
// 定义特定的删除器
struct MemoryPoolDeleter {
IMemoryPool* pool;
void operator()(void* ptr) const {
if (pool && ptr) pool->release(ptr);
}
};
// 别名定义
using RawPayload = std::unique_ptr<DataObject, MemoryPoolDeleter>;
using RawDataPacket = DataPacket<RawPayload>;
```
### 3.2 结果数据包 (`DetectionPacket` / `TrackPacket`)
- **场景**`SignalProcessor` -\> `DataProcessor` -\> `DisplayController`。数据量较小KB 级),使用堆内存或对齐分配器。
- **Payload 类型**`std::vector<DetectionResult>` (Aligned)。
- **所有权逻辑**
- `std::vector` 本身就是 RAII 容器。
- `DataPacket` 的移动会自动触发 `vector` 的移动(仅交换内部指针 `begin/end/capacity`成本极低3 个指针大小)。
- **注意**:此处不需要自定义删除器,除非我们想引入“对象池”来复用 vector 的内存(对于 100Hz 的频率,`std::vector` 的默认分配器性能通常可以接受,暂不引入对象池以降低复杂度)。
<!-- end list -->
```cpp
// 别名定义
// 使用 2.5.1 定义的对齐容器
using DetectionPayload = AlignedVector<DetectionResult>;
using DetectionPacket = DataPacket<DetectionPayload>;
using TrackPayload = AlignedVector<TrackData>;
using TrackPacket = DataPacket<TrackPayload>;
```
-----
## 4\. 辅助工厂方法 (Factory Helpers)
为了简化 Header 的填充(防止开发者忘记填 TraceID应提供工厂函数。
```cpp
template <typename T>
DataPacket<T> MakePacket(T&& payload, uint64_t seq_id) {
DataPacket<T> packet;
// 自动捕获当前上下文
packet.header.trace_id = TraceContext::getCurrentId();
packet.header.timestamp_us = Clock::nowInUs();
packet.header.sequence_id = seq_id;
packet.header.source_module_id = ModuleContext::getCurrentModuleId();
packet.header.flags = 0;
// 移动负载
packet.payload = std::move(payload);
return packet;
}
```
-----
## 总结
**2.5.4 章节基线** 已确立为:
1. **Generic Envelope**:统一的 `DataPacket<T>` 模板,强制包含 Header。
2. **Move-Only**:通过删除拷贝构造函数,物理上杜绝深拷贝。
3. **Hybrid Payload Strategy**
- 大内存Raw`unique_ptr` + `CustomDeleter` (Pool)。
- 小内存Result`std::vector` (Move Semantics)。
这一设计确保了数据在“集装箱”里流转时,既安全(不会泄露),又轻快(只有指针在动)。