C++ CustomStack详细教程
本文实现了一个线程安全的自定义栈(CustomStack),主要功能包括:1. 基本栈操作:初始化(stack_init)、压栈(stack_push)、弹栈(stack_pop)、查看(stack_peek);2. 内存管理:支持动态调整栈大小(stack_resize);3. 线程安全:所有操作通过std::lock_guard加锁;4. 事件监听:可注册回调函数(stack_register
·
代码分析
这段代码实现了一个线程安全的自定义栈(CustomStack),包含初始化、压栈、弹栈、监听等功能。以下是关键部分的解析:
核心功能实现
栈初始化 (stack_init)
检查参数有效性后分配内存,初始化栈顶指针(top)和监听相关字段(callback、threshold)。通过宏 ENABLE_STACK_CHECK 控制是否启用内存分配检查。
压栈操作 (stack_push)
检查栈剩余空间,通过 memcpy 写入数据并更新栈顶指针。若启用监听且达到阈值(threshold),触发 STACK_EVENT_USED_THRESHOLD 事件。
弹栈操作 (stack_pop)
检查栈是否为空或数据长度是否合法,通过 memcpy 读取数据并清空原位置内存。触发 STACK_EVENT_POP 事件。
监听机制 (trigger_listener)
通过异步线程调用回调函数,传递事件类型、栈总大小、已用大小和阈值。使用 std::lock_guard 确保线程安全。
线程安全设计
- 所有操作均通过
std::lock_guard<std::mutex>加锁,避免多线程竞争。 - 监听回调通过
std::thread异步执行,避免阻塞主逻辑。 - 检查
new_size是否小于当前已用空间(top)。 - 更新
stack_size字段和可能的阈值校验。 - 处理
realloc失败时的回滚策略。
StackStatus stack_resize(CustomStack* stack, size_t new_size) {
if (!stack || new_size == 0) {
std::cerr << "[Stack Error] Resize failed: invalid params!" << std::endl;
return STACK_MEMORY_ERROR;
}
std::lock_guard<std::mutex> guard(stack->lock);
if (stack->top > new_size) {
std::cerr << "[Stack Error] Resize failed: new size smaller than used space!" << std::endl;
return STACK_OUT_OF_BOUNDS;
}
uint8_t* new_buffer = (uint8_t*)realloc(stack->buffer, new_size);
if (!new_buffer) {
std::cerr << "[Stack Error] Resize failed: memory reallocation failed!" << std::endl;
return STACK_MEMORY_ERROR;
}
stack->buffer = new_buffer;
stack->stack_size = new_size;
return STACK_OK;
}
#include "./include/stack_memory.h"
void trigger_listener(CustomStack* stack, StackEventType event) {
if (!stack || !stack->enable_listener || !stack->callback) {
return;
}
std::lock_guard<std::mutex> guard(stack->lock);
size_t used = stack->top;
size_t total = stack->stack_size;
size_t threshold = stack->threshold;
std::thread([=]() {
stack->callback(event, total, used, threshold);
}).detach();
}
StackStatus stack_init(CustomStack* stack, size_t stack_size) {
if (stack == nullptr) {
std::cerr << "[Stack Error] Init failed: stack pointer is null!" << std::endl;
return STACK_MEMORY_ERROR;
}
std::lock_guard<std::mutex> guard(stack->lock);
#ifdef ENABLE_STACK_CHECK
#if ENABLE_STACK_CHECK == 1
if (IS_STACK_INVALID_OR_FULL(stack, stack_size)) {
std::cerr << "[Stack Error] Init failed: invalid params (null or full or size 0)!" << std::endl;
return STACK_MEMORY_ERROR;
}
stack->buffer = (uint8_t*)malloc(stack_size);
if (stack->buffer == nullptr) {
std::cerr << "Stack memory allocation failed!" << std::endl;
return STACK_MEMORY_ERROR;
}
memset(stack->buffer, 0, stack_size);
#else
stack->buffer = nullptr;
#endif
#endif
stack->stack_size = stack_size;
stack->top = 0;
stack->callback = nullptr;
stack->threshold = 0;
stack->enable_listener = false;
return STACK_OK;
}
StackStatus stack_push(CustomStack* stack, const void* data, size_t data_len) {
if (stack == nullptr || data == nullptr || data_len == 0) {
std::cerr << "[Stack Error] Push failed: invalid params!" << std::endl;
return STACK_OUT_OF_BOUNDS;
}
std::lock_guard<std::mutex> guard(stack->lock);
if (stack->top + data_len > stack->stack_size) {
std::cerr << "[Stack Error] Push failed: stack full (used: " << stack->top << ", need: " << data_len << ")!" << std::endl;
trigger_listener(stack, STACK_EVENT_FULL);
return STACK_FULL;
}
memcpy(stack->buffer + stack->top, data, data_len);
stack->top += data_len;
trigger_listener(stack, STACK_EVENT_PUSH);
if (stack->threshold > 0 && stack->top >= stack->threshold) {
trigger_listener(stack, STACK_EVENT_USED_THRESHOLD);
}
return STACK_OK;
}
StackStatus stack_pop(CustomStack* stack, void* out_data, size_t data_len) {
if (stack == nullptr || out_data == nullptr || data_len == 0) {
std::cerr << "[Stack Error] Pop failed: invalid params!" << std::endl;
return STACK_OUT_OF_BOUNDS;
}
std::lock_guard<std::mutex> guard(stack->lock);
if (stack->top == 0 || stack->top < data_len) {
std::cerr << "[Stack Error] Pop failed: stack empty or data len too big (used: " << stack->top << ")!" << std::endl;
trigger_listener(stack, STACK_EVENT_EMPTY);
return STACK_EMPTY;
}
stack->top -= data_len;
memcpy(out_data, stack->buffer + stack->top, data_len);
memset(stack->buffer + stack->top, 0, data_len);
trigger_listener(stack, STACK_EVENT_POP);
return STACK_OK;
}
StackStatus stack_peek(CustomStack* stack, void* out_data, size_t data_len) {
if (stack == nullptr || out_data == nullptr || data_len == 0) {
return STACK_OUT_OF_BOUNDS;
}
std::lock_guard<std::mutex> guard(stack->lock);
if (stack->top == 0 || stack->top < data_len) {
return STACK_EMPTY;
}
memcpy(out_data, stack->buffer + (stack->top - data_len), data_len);
return STACK_OK;
}
bool stack_is_empty(CustomStack* stack) {
if (stack == nullptr) return true;
std::lock_guard<std::mutex> guard(stack->lock);
return stack->top == 0;
}
bool stack_is_full(CustomStack* stack) {
if (stack == nullptr) return false;
std::lock_guard<std::mutex> guard(stack->lock);
return stack->top == stack->stack_size;
}
size_t stack_used_size(CustomStack* stack) {
if (stack == nullptr) return 0;
std::lock_guard<std::mutex> guard(stack->lock);
return stack->top;
}
void stack_register_listener(CustomStack* stack, StackCallback cb, size_t threshold) {
if (!stack) return;
std::lock_guard<std::mutex> guard(stack->lock);
stack->callback = cb;
stack->threshold = threshold;
}
void stack_enable_listener(CustomStack* stack, bool enable) {
if (!stack) return;
std::lock_guard<std::mutex> guard(stack->lock);
stack->enable_listener = enable;
}
StackStatus stack_resize(CustomStack* stack, size_t new_size) {
if (!stack || new_size == 0) {
std::cerr << "[Stack Error] Resize failed: invalid params!" << std::endl;
return STACK_MEMORY_ERROR;
}
std::lock_guard<std::mutex> guard(stack->lock);
uint8_t* new_buffer = (uint8_t*)realloc(stack->buffer, new_size);
if (!new_buffer) {
std::cerr << "[Stack Error] Resize failed: memory allocation failed!" << std::endl;
return STACK_MEMORY_ERROR;
}
if (new_size < stack->top) {
stack->top = new_size;
memset(new_buffer + stack->top, 0, new_size - stack->top);
}
stack->buffer = new_buffer;
stack->stack_size = new_size;
trigger_listener(stack, STACK_EVENT_SIZE_CHANGED);
return STACK_OK;
}
void stack_destroy(CustomStack* stack) {
if (!stack) return;
std::lock_guard<std::mutex> guard(stack->lock);
if (stack->buffer != nullptr) {
free(stack->buffer);
stack->buffer = nullptr;
}
stack->stack_size = 0;
stack->top = 0;
stack->callback = nullptr;
stack->threshold = 0;
stack->enable_listener = false;
}
更多推荐



所有评论(0)