FreeRTOS调用xSemaphoreTake后无限阻塞且无上下文切换问题
问题根源与解决方案
核心问题1:全局对象初始化时机早于FreeRTOS调度器启动
你的os2::thread2 th{};是全局对象,它的构造函数会在FreeRTOS调度器启动前执行(也就是app_main运行之前,甚至早于系统初始化FreeRTOS内核)。
在FreeRTOS规则中:
- 调用
xTaskCreateStaticPinnedToCore创建任务后,任务仅会被加入就绪队列,但调度器未启动时,任务永远不会被调度执行。 xSemaphoreTake(..., portMAX_DELAY)在调度器未启动时,不会触发任务切换——因为FreeRTOS的任务切换依赖调度器的时钟节拍或主动触发的调度逻辑,此时内核还未运行,调用该函数会直接进入死循环,永远等不到信号量。
这就是程序仅输出init! Hello World!后停滞的原因:构造函数卡在xSemaphoreTake,worker任务根本没机会运行。
核心问题2:局部变量生命周期风险(次要但必须修复)
你的comm_obj comm是thread2构造函数里的局部变量,即使调度器能正常启动,当构造函数执行完毕退出后,comm会被销毁,worker任务里通过param访问的comm.sem会变成野指针,导致未定义行为。
修复步骤
步骤1:将对象初始化移到FreeRTOS调度器启动后
把thread2的创建从全局变量移到app_main里,确保在FreeRTOS内核运行后再执行任务创建和同步逻辑:
修改main.cpp:
#include "thread2.hpp" extern "C" auto app_main() -> void { os2::thread2 th{}; // 此时调度器已启动 vTaskDelay(portMAX_DELAY); };
步骤2:修正comm_obj的生命周期
把comm_obj改为thread2的成员变量,避免局部变量销毁导致的野指针:
修改thread2.hpp:
#include <cstdio> #include <array> #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "freertos/semphr.h" namespace os2 { struct comm_obj { SemaphoreHandle_t sem; StaticSemaphore_t sem_buffer; // 把静态信号量缓冲区也放到成员中 }; inline auto worker(void* const param) -> void { printf("Worker task before giving semaphore\n"); fflush(stdout); auto& comm = *static_cast<comm_obj*>(param); xSemaphoreGive(comm.sem); printf("Worker after giving semaphore!\n"); fflush(stdout); vTaskDelete(NULL); } struct thread2 { thread2() { printf("init!\n"); // 初始化成员变量里的信号量 comm_.sem = xSemaphoreCreateBinaryStatic(&comm_.sem_buffer); printf("Hello "); fflush(stdout); [[maybe_unused]] TaskHandle_t handle = xTaskCreateStaticPinnedToCore( &worker, "default", 5*1024, &comm_, // 传递成员变量的地址 10, stack_.data(), &tcb_, 0); printf("World!\n"); fflush(stdout); xSemaphoreTake(comm_.sem, portMAX_DELAY); } StaticTask_t tcb_; std::array<StackType_t, 5*1024> stack_; comm_obj comm_; // 作为成员变量保存,避免生命周期问题 }; }
验证修复效果
修复后程序会输出:
init! Hello World! Worker task before giving semaphore Worker after giving semaphore!
之后app_main进入延迟状态,不会触发任务看门狗。
内容的提问来源于stack exchange,提问作者glades
相关产品推荐
相关产品推荐

