262 lines
8.7 KiB
C++
262 lines
8.7 KiB
C++
#include "SM_RingBuffer.h"
|
|
|
|
#include "Core/spdlog/export.h"
|
|
#include "Core/transmit_protocol/Channel_Simulator/global.h"
|
|
#include "Core/Base/global_include.h"
|
|
|
|
namespace Psc {
|
|
// 1. used_space 简化:利用无符号溢出特性或 mask
|
|
size_t SM_Base_RingBuffer::used_space() const {
|
|
// 统一使用 mask 处理回绕,消除 if 判断
|
|
return (state->tail - state->head) & mask;
|
|
}
|
|
|
|
// 2. free_space:保持浪费一个字节的策略,确保 tail 永远不会追上 head 导致重合
|
|
size_t SM_Base_RingBuffer::free_space() const {
|
|
// 逻辑容量是 capacity - 1
|
|
return (state->capacity - 1) - used_space();
|
|
}
|
|
|
|
// 3. 判定函数
|
|
[[nodiscard]] bool SM_Base_RingBuffer::empty() const {
|
|
return state->head == state->tail;
|
|
}
|
|
|
|
[[nodiscard]] bool SM_Base_RingBuffer::full() const {
|
|
// 如果 tail 的下一个位置是 head,则为满
|
|
return ((state->tail + 1) & mask) == state->head;
|
|
}
|
|
|
|
// 4. rollback 优化:同样使用 mask 替代 %
|
|
void SM_Base_RingBuffer::rollback(size_t n) {
|
|
// (head - n) 可能产生负数溢出,但在无符号下配合 mask 是正确的
|
|
state->head = (state->head - n) & mask;
|
|
}
|
|
SM_Base_RingBuffer::SM_Base_RingBuffer(const std::string &name, size_t size) {
|
|
init(name, size);
|
|
}
|
|
|
|
void SM_Base_RingBuffer::init(const std::string &name, size_t size) {
|
|
data_mutex.init(name + "_data_mutex");
|
|
create_mutex.init(name + "_create_mutex");
|
|
std::lock_guard lock(create_mutex);
|
|
|
|
// --- 修改点 1: 确保数据区本身是 2 的幂 ---
|
|
size_t data_size_pow2 = ceilToPow2(size + 1);
|
|
size_t total_alloc_size = sizeof(SharedMemoryState) + data_size_pow2;
|
|
|
|
bool ok;
|
|
std::ostringstream oss;
|
|
bool open = check_if_shared_memory_exists(name);
|
|
|
|
if (open) {
|
|
// 注意:打开时也要使用计算出的 total_alloc_size
|
|
oss << "【打开共享内存】" << VAR_STR_3(name, total_alloc_size, size) << std::endl;
|
|
ok = shm.open(name, total_alloc_size);
|
|
create = false;
|
|
} else {
|
|
oss << "【创建共享内存】" << VAR_STR_3(name, total_alloc_size, size) << std::endl;
|
|
ok = shm.create(name, total_alloc_size);
|
|
create = true;
|
|
}
|
|
|
|
if (!ok) {
|
|
std::cerr << oss.str() << "无法创建或打开共享内存!" << std::endl;
|
|
Psc::fail_fast();
|
|
}
|
|
|
|
state = reinterpret_cast<SharedMemoryState *>(shm.data());
|
|
uint8_t *raw = shm.data();
|
|
|
|
if (!open) {
|
|
// --- 修改点 2: 直接存储 2 的幂 ---
|
|
state->capacity = data_size_pow2;
|
|
state->head = 0;
|
|
state->tail = 0;
|
|
} else {
|
|
if (state->capacity == 0 || (state->capacity & mask) != 0) {
|
|
std::cerr << "致命错误:共享内存容量非法,必须为 2 的幂!" << std::endl;
|
|
Psc::fail_fast();
|
|
}
|
|
}
|
|
|
|
// --- 修改点 3: 这里的 mask 赋值必须在获取 state 之后,无论 open 还是 create 都要执行 ---
|
|
mask = state->capacity - 1;
|
|
buffer = raw + sizeof(SharedMemoryState);
|
|
|
|
// 打印调试信息
|
|
oss.str(""); // 清空
|
|
oss << "\t实际分配容量 (2^n): " << state->capacity << std::endl;
|
|
oss << "\tMask: " << std::hex << mask << std::dec << std::endl;
|
|
std::cout << oss.str();
|
|
}
|
|
|
|
|
|
SM_Base_RingBuffer::SM_Base_RingBuffer() = default;
|
|
SM_Base_RingBuffer::~SM_Base_RingBuffer() {
|
|
// 尤其注意不要删除共享内存删除会导致共享内存很奇怪
|
|
shm.close(); // 关闭共享内存
|
|
}
|
|
std::string SM_Base_RingBuffer::state_str() {
|
|
return std::to_string(state->head) + "," + std::to_string(state->tail) + "," + std::to_string(state->capacity);
|
|
}
|
|
void SM_Base_RingBuffer::write_bytes(const uint8_t *data, size_t len) {
|
|
// 计算到缓冲区末尾的距离
|
|
size_t end = std::min(len, state->capacity - state->tail);
|
|
|
|
std::memcpy(buffer + state->tail, data, end);
|
|
std::memcpy(buffer, data + end, len - end);
|
|
|
|
// 优化点:使用 & 代替 %
|
|
state->tail = (state->tail + len) & mask;
|
|
}
|
|
|
|
void SM_Base_RingBuffer::read_bytes(uint8_t *data, size_t len) {
|
|
size_t end = std::min(len, state->capacity - state->head);
|
|
|
|
std::memcpy(data, buffer + state->head, end);
|
|
std::memcpy(data + end, buffer, len - end);
|
|
|
|
// 优化点:使用 & 代替 %
|
|
state->head = (state->head + len) & mask;
|
|
}
|
|
|
|
void SM_Base_RingBuffer::peek_bytes(uint8_t *data, size_t len) const {
|
|
size_t end = std::min(len, state->capacity - state->head);
|
|
std::memcpy(data, buffer + state->head, end);
|
|
std::memcpy(data + end, buffer, len - end);
|
|
// 不更新 state->head
|
|
}
|
|
|
|
bool SM_RingBuffer::write(const uint8_t *src, size_t len) {
|
|
std::lock_guard lock(data_mutex);
|
|
size_t need = HEADER_SIZE + len;
|
|
|
|
// 包模式:空间不够直接返回 false,不能拆分写入
|
|
if (free_space() < need) return false;
|
|
|
|
auto header = static_cast<uint32_t>(len);
|
|
write_bytes(reinterpret_cast<const uint8_t*>(&header), HEADER_SIZE);
|
|
write_bytes(src, len);
|
|
return true;
|
|
}
|
|
|
|
bool SM_RingBuffer::read(uint8_t *out, size_t &out_len) {
|
|
std::lock_guard lock(data_mutex);
|
|
if (empty()) return false;
|
|
|
|
uint32_t msg_len;
|
|
// 1. 尝试读包头
|
|
peek_bytes(reinterpret_cast<uint8_t*>(&msg_len), HEADER_SIZE);
|
|
|
|
// 2. 检查包体是否已全部到达(流中可能只有半个包)
|
|
if (used_space() < HEADER_SIZE + msg_len) return false;
|
|
|
|
// 3. 正式读取
|
|
size_t dummy_header_len;
|
|
read_bytes(reinterpret_cast<uint8_t*>(&dummy_header_len), HEADER_SIZE); // 移动 head 指针过 Header
|
|
read_bytes(out, msg_len); // 读取 Body
|
|
|
|
out_len = msg_len;
|
|
return true;
|
|
}
|
|
|
|
|
|
bool SM_Stream_RingBuffer::write(const uint8_t *src, size_t len) {
|
|
if (len == 0) return true;
|
|
std::lock_guard lock(data_mutex);
|
|
|
|
if (free_space() < len) return false;
|
|
|
|
write_bytes(src, len);
|
|
return true;
|
|
}
|
|
|
|
bool SM_Stream_RingBuffer::read(uint8_t *out, size_t &out_len) {
|
|
if (out_len == 0) return true;
|
|
std::lock_guard lock(data_mutex);
|
|
|
|
if (used_space() < out_len) {
|
|
out_len = 0;
|
|
return false;
|
|
}
|
|
|
|
read_bytes(out, out_len);
|
|
return true;
|
|
}
|
|
|
|
// --- Best Effort 读写:尽可能操作,返回实际处理的字节数 ---
|
|
|
|
size_t SM_Stream_RingBuffer::write_best_effort(const uint8_t *src, size_t len) {
|
|
if (len == 0) return 0;
|
|
std::lock_guard lock(data_mutex);
|
|
|
|
size_t can_write = free_space();
|
|
size_t actual_len = std::min(len, can_write);
|
|
|
|
if (actual_len > 0) {
|
|
write_bytes(src, actual_len);
|
|
}
|
|
return actual_len;
|
|
}
|
|
|
|
size_t SM_Stream_RingBuffer::read_best_effort(uint8_t *out, size_t max_len) {
|
|
if (max_len == 0) return 0;
|
|
std::lock_guard lock(data_mutex);
|
|
|
|
size_t can_read = used_space();
|
|
size_t actual_len = std::min(max_len, can_read);
|
|
|
|
if (actual_len > 0) {
|
|
read_bytes(out, actual_len);
|
|
}
|
|
return actual_len;
|
|
}
|
|
|
|
} // namespace Psc
|
|
|
|
#ifdef _USE_GTEST
|
|
#include <gtest/gtest.h>
|
|
|
|
// TEST(Shared_Memory_Test, Normal_Shared_Memory) {
|
|
// std::cout << "共享内存测试开始!" << std::endl;
|
|
//
|
|
//
|
|
// int n = 1000;
|
|
// std::thread t1([&]() {
|
|
// Psc::SM_RingBuffer sm;
|
|
// sm.init("test", 1000);
|
|
// int i = 0;
|
|
// while (i++ < n) {
|
|
// auto size = generate_random_size(15, 20);
|
|
// auto data2 = generate_random_string(size);
|
|
// auto data = std::to_string(i) + "______123456789____" + data2;
|
|
// sm.write((const uint8_t *)data.data(), data.size());
|
|
// // std::this_thread::sleep_for(std::chrono::milliseconds(1000));
|
|
// }
|
|
// });
|
|
//
|
|
// std::thread t2([&]() {
|
|
// Psc::SM_RingBuffer sm;
|
|
// sm.init("test", 1000);
|
|
// int i = 1;
|
|
// while (true) {
|
|
// uint8_t buf[4096];
|
|
// size_t len;
|
|
// auto ok = sm.read(buf, len);
|
|
// while (ok) {
|
|
// std::cout << VAR_STR_1(len) << std::string((char*)buf, len) << std::endl;
|
|
// ok = sm.read(buf, len);
|
|
// if (++i == n) break;
|
|
// }
|
|
// // std::this_thread::sleep_for(std::chrono::milliseconds(1000));
|
|
// }
|
|
// });
|
|
//
|
|
// t1.join();
|
|
// t2.join();
|
|
//
|
|
//
|
|
// }
|
|
|
|
#endif |