Files
Inbox/系统基座文件/2/2.5/2.5.4 零拷贝数据容器规范 (Zero-Copy Data Container Specification).md
2025-12-11 07:24:36 +08:00

177 lines
6.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
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)。
这一设计确保了数据在“集装箱”里流转时,既安全(不会泄露),又轻快(只有指针在动)。