printf引发死锁问题

printf引发死锁

printf函数执行的大体步骤如下图所示,当printf函数在执行过程中,它会请求并获得一些系统锁。这时候若是被一个信号处理程序打断,如右图所示,并信号处理程序中执行printf函数,那么就没有办法获取到该锁,也因此便发生了死锁。
以上便是printf函数会导致死锁问题的原因。
在这里插入图片描述
printf(fprintf,sprintf)实现了缓冲IO,因此需要加锁才能共享缓冲区,如下图所示。
这也是printf函数执行过程中需要获取锁的原因。
在这里插入图片描述

### 如何在 FreeRTOS 中正确使用 `printf` 函数 #### 解决方案概述 为了使 `printf` 函数能够在基于 FreeRTOS 的嵌入式系统中正常工作,需要解决两个主要问题:确保 `printf` 是可重入的以及正确配置 UART 接口来处理字符输。 #### 配置 UART 输接口 为了让 `printf` 能够通过 UART 发送数据,在项目初始化部分需定义标准库函数 `fputc()` 来实现单字节发送功能。具体做法是在 `usart.c` 文件中的适当位置添加如下代码片段[^3]: ```c /* USER CODE BEGIN 1 */ int fputc(int ch, FILE *f) { uint8_t c = (uint8_t)ch; HAL_UART_Transmit(&huart1, &c, 1, 2); return c; } /* USER CODE END 1 */ ``` 这段代码实现了将要打印的数据转换成适合硬件传输的形式,并调用了 STM32 HAL 库提供的 `HAL_UART_Transmit()` 函数完成实际的数据传送操作。 #### 处理任务调度冲突 当多个任务尝试同时执行 `printf` 操作时可能会引发资源竞争问题,进而影响系统的稳定性甚至造成死锁情况发生。为了避免这种情况的发生,可以考虑采用互斥量(mutex)机制保护共享资源访问过程;另一种方法则是减少或避免在同一时间点上有超过一个的任务试图进行 I/O 操作[^4]。 对于那些频繁调用 `printf` 的场景来说,建议创建专门的日志记录任务负责收集来自不同源的信息并有序地将其输到终端设备上。这样不仅可以提高效率还能有效防止因并发引起的潜在风险。 #### 实现非阻塞式的日志记录方式 考虑到实时操作系统的特点及其应用场景需求,推荐设计一种异步模式下的日志管理策略——即每当有新的消息到来时就立即将其存放到环形缓冲区(circular buffer),而后再由后台线程定期读取这些待处理项并通过串行端口逐条发。这种方法不仅能够显著降低 CPU 占用率而且有助于提升整体性能表现。 下面给一段简单的 C++风格伪代码作为参考: ```cpp // 定义全局变量存储指向当前可用空间指针的位置信息 volatile static char* pWritePos; void log(const char* msg){ // 将新接收到的消息追加至队列末端... } void vLogTask(void *pvParameters){ while(1){ if(/*存在未处理过的日志*/){ /*从pWritePos处取一条完整的字符串*/ sendViaUart(logEntry); } // 让CPU给其他更高优先级的工作去做 vTaskDelay(pdMS_TO_TICKS(1)); } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值