代码分析

这段代码实现了一个线程安全的自定义栈(CustomStack),包含初始化、压栈、弹栈、监听等功能。以下是关键部分的解析:


核心功能实现

栈初始化 (stack_init)
检查参数有效性后分配内存,初始化栈顶指针(top)和监听相关字段(callbackthreshold)。通过宏 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;
}

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐