Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
log
已开启线程打印安全,多线程输出日志感觉还是会互相抢占打断
发布于 2024-03-18 15:51:35 浏览:341
订阅该版
如题。 ![screenshot_f0315d503975a8b752468568b4e0bb8.png](https://oss-club.rt-thread.org/uploads/20240318/c1b10e964d913739f0bf8b22d4e1efb7.png) ![screenshot_37cf03044c1405d551997462f3729fd.png](https://oss-club.rt-thread.org/uploads/20240318/f7843e0bc01e9e196a085b4e0dc08130.png)
查看更多
2
个回答
默认排序
按发布时间排序
聚散无由
2024-03-19
https://jswyll.com/
## 问题分析 在各个文件中定义打印标签和打印等级,使用`LOG_D`、`LOG_I`、`LOG_W`或`LOG_E`打印: ```c #define DBG_TAG "main" #define DBG_LVL DBG_LOG #include
int main(void) { LOG_D("This is a debug message"); LOG_I("This is an information message"); LOG_W("This is a warning message"); LOG_E("This is an error message"); return RT_EOK; } ``` 相关文件是`rtdbg.h`,其中指定文件的DBG_LVL决定了是否打印对应等级即以上的日志。其中关键的宏定义是: ```c #define dbg_log_line(lvl, color_n, fmt, ...) \ do \ { \ _DBG_LOG_HDR(lvl, color_n); \ rt_kprintf(fmt, ##__VA_ARGS__); \ _DBG_LOG_X_END; \ } \ while (0) ``` 以`LOG_I`、启用颜色打印为例,依次展开LOG_I: 1. 根据对应的等级,启用LOG_I打印: ```c #define LOG_I(fmt, ...) dbg_log_line("I", 32, fmt, ##__VA_ARGS__) ``` 2. 展开dbg_log_line: ```c #define LOG_I(fmt, ...) do \ { \ _DBG_LOG_HDR("I", 32); \ rt_kprintf(fmt, ##__VA_ARGS__); \ _DBG_LOG_X_END; \ } \ while (0) ``` 3. 分别展开`_DBG_LOG_HDR`和`_DBG_LOG_X_END`: ```c #define LOG_I(fmt, ...) do \ { \ rt_kprintf("\033[32m[I/" DBG_SECTION_NAME "] ") \ rt_kprintf(fmt, ##__VA_ARGS__); \ rt_kprintf("\033[0m\n"); \ } \ while (0) ``` 其中: - 两个带常量字符串会被合并,例如DBG_SECTION_NAME如果是`"main"`,`rt_kprintf("\033[32m[I/" DBG_SECTION_NAME "] ")`最终为`rt_kprintf("\033[32m[I/main] ")`; - `##__VA_ARGS__`表示展开`LOG_I(fmt, ...)`中的`...`; - `\033[数值m`表示设置字体的前景色。`_DBG_LOG_HDR`的32表示绿色,`_DBG_LOG_X_END`的0表示重置颜色; - `#define xxx do{xxx}while (0)`是一个宏定义展开为多条语句的方法。 **可见,语句LOG_X语言被分成了三部分:设置颜色和标签头;打印实体;重置颜色并换行。** **因此,rt_kprintf函数线程安全也会导致日志输出的顺序不一致。** 例如你的: ```plaintext [W/bms rtu][w/dsp rtu] receive timeout. receive timeout ``` 第一行有颜色,第二行没有颜色,且有些错位。可以猜出它的顺序是: 1. 颜色+标签头`[W/bms rtu]`; 2. 颜色+标签头`[W/bms rtu]`; 3. receive timeout. 4. 重置颜色+换行; 5. receive timeout. 6. 重置颜色+换行; ### 解决方案 从上面的分析可知,对于一行原始语句的打印,它本身是线程安全的,但加上颜色标头和换行以后就有点乱了。无伤大雅,如果要整体线程安全,可以把dbg_log_line宏定义展开的语句合并为一行: ```c #define dbg_log_line(lvl, color_n, fmt, ...) \ rt_kprintf(_DBG_HDR(lvl, color_n) fmt _DBG_X_END, ##__VA_ARGS__) ``` 其中,`_DBG_HDR(lvl, color_n)`和`_DBG_X_END`定义如下: ```c #ifdef DBG_COLOR #define _DBG_COLOR(n) rt_kprintf("\033["#n"m") #define _DBG_HDR(lvl_name, color_n) \ "\033["#color_n"m[" lvl_name "/" DBG_SECTION_NAME "] " #define _DBG_X_END \ "\033[0m\n" #else #define _DBG_COLOR(n) #define _DBG_HDR(lvl_name, color_n) \ "[" lvl_name "/" DBG_SECTION_NAME "] " #define _DBG_X_END \ "\n" #endif /* DBG_COLOR */ ``` 修改后的rtdbg.h如下: ```c /* * Copyright (c) 2006-2021, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date Author Notes * 2016-11-12 Bernard The first version * 2018-05-25 armink Add simple API, such as LOG_D, LOG_E */ /* * The macro definitions for debug * * These macros are defined in static. If you want to use debug macro, you can * use as following code: * * In your C/C++ file, enable/disable DEBUG_ENABLE macro, and then include this * header file. * * #define DBG_TAG "MOD_TAG" * #define DBG_LVL DBG_INFO * #include
// must after of DBG_LVL, DBG_TAG or other options * * Then in your C/C++ file, you can use LOG_X macro to print out logs: * LOG_D("this is a debug log!"); * LOG_E("this is a error log!"); */ #ifndef RT_DBG_H__ #define RT_DBG_H__ #include
#ifdef __cplusplus extern "C" { #endif /* the debug log will force enable when RT_DEBUG macro is defined */ #if defined(RT_DEBUG) && !defined(DBG_ENABLE) #define DBG_ENABLE #endif /* it will force output color log when RT_DEBUG_COLOR macro is defined */ #if defined(RT_DEBUG_COLOR) && !defined(DBG_COLOR) #define DBG_COLOR #endif #if defined(RT_USING_ULOG) /* using ulog compatible with rtdbg */ #include
#else /* DEBUG level */ #define DBG_ERROR 0 #define DBG_WARNING 1 #define DBG_INFO 2 #define DBG_LOG 3 #ifdef DBG_TAG #ifndef DBG_SECTION_NAME #define DBG_SECTION_NAME DBG_TAG #endif #else /* compatible with old version */ #ifndef DBG_SECTION_NAME #define DBG_SECTION_NAME "DBG" #endif #endif /* DBG_TAG */ #ifdef DBG_ENABLE #ifdef DBG_LVL #ifndef DBG_LEVEL #define DBG_LEVEL DBG_LVL #endif #else /* compatible with old version */ #ifndef DBG_LEVEL #define DBG_LEVEL DBG_WARNING #endif #endif /* DBG_LVL */ /* * The color for terminal (foreground) * BLACK 30 * RED 31 * GREEN 32 * YELLOW 33 * BLUE 34 * PURPLE 35 * CYAN 36 * WHITE 37 */ #ifdef DBG_COLOR #define _DBG_COLOR(n) rt_kprintf("\033["#n"m") #define _DBG_HDR(lvl_name, color_n) \ "\033["#color_n"m[" lvl_name "/" DBG_SECTION_NAME "] " #define _DBG_LOG_HDR(lvl_name, color_n) \ rt_kprintf("\033["#color_n"m[" lvl_name "/" DBG_SECTION_NAME "] ") #define _DBG_X_END \ "\033[0m\n" #define _DBG_LOG_X_END \ rt_kprintf("\033[0m\n") #else #define _DBG_COLOR(n) #define _DBG_HDR(lvl_name, color_n) \ "[" lvl_name "/" DBG_SECTION_NAME "] " #define _DBG_LOG_HDR(lvl_name, color_n) \ rt_kprintf("[" lvl_name "/" DBG_SECTION_NAME "] ") #define _DBG_X_END \ "\n" #define _DBG_LOG_X_END \ rt_kprintf("\n") #endif /* DBG_COLOR */ /* * static debug routine * NOTE: This is a NOT RECOMMENDED API. Please using LOG_X API. * It will be DISCARDED later. Because it will take up more resources. */ #define dbg_log(level, fmt, ...) \ if ((level) <= DBG_LEVEL) \ { \ switch(level) \ { \ case DBG_ERROR: _DBG_LOG_HDR("E", 31); break; \ case DBG_WARNING: _DBG_LOG_HDR("W", 33); break; \ case DBG_INFO: _DBG_LOG_HDR("I", 32); break; \ case DBG_LOG: _DBG_LOG_HDR("D", 0); break; \ default: break; \ } \ rt_kprintf(fmt, ##__VA_ARGS__); \ _DBG_COLOR(0); \ } #define dbg_here \ if ((DBG_LEVEL) <= DBG_LOG){ \ rt_kprintf(DBG_SECTION_NAME " Here %s:%d\n", \ __FUNCTION__, __LINE__); \ } #define dbg_log_line(lvl, color_n, fmt, ...) \ rt_kprintf(_DBG_HDR(lvl, color_n) fmt _DBG_X_END, ##__VA_ARGS__) #define dbg_raw(...) rt_kprintf(__VA_ARGS__); #else #define dbg_log(level, fmt, ...) #define dbg_here #define dbg_enter #define dbg_exit #define dbg_log_line(lvl, color_n, fmt, ...) #define dbg_raw(...) #endif /* DBG_ENABLE */ #if (DBG_LEVEL >= DBG_LOG) #define LOG_D(fmt, ...) dbg_log_line("D", 0, fmt, ##__VA_ARGS__) #else #define LOG_D(...) #endif #if (DBG_LEVEL >= DBG_INFO) #define LOG_I(fmt, ...) dbg_log_line("I", 32, fmt, ##__VA_ARGS__) #else #define LOG_I(...) #endif #if (DBG_LEVEL >= DBG_WARNING) #define LOG_W(fmt, ...) dbg_log_line("W", 33, fmt, ##__VA_ARGS__) #else #define LOG_W(...) #endif #if (DBG_LEVEL >= DBG_ERROR) #define LOG_E(fmt, ...) dbg_log_line("E", 31, fmt, ##__VA_ARGS__) #else #define LOG_E(...) #endif #define LOG_RAW(...) dbg_raw(__VA_ARGS__) #endif /* defined(RT_USING_ULOG) && define(DBG_ENABLE) */ #ifdef __cplusplus } #endif #endif /* RT_DBG_H__ */ ``` 改动了两处: ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20240319/77a5c2721d02e01420302161ddd09de6.png.webp) ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20240319/29cc002462d4e23826a40dbd8ed0337c.png.webp)
a1012112796
2024-03-19
这家伙很懒,什么也没写!
因为 ulog 打印用的不是 rt_kprintf, 这个选项是保护 rt_kprintf 的。
撰写答案
登录
注册新账号
关注者
0
被浏览
341
关于作者
AVR_DIY
这家伙很懒,什么也没写!
提问
4
回答
6
被采纳
0
关注TA
发私信
相关问题
1
版本发布时怎样关闭LOG_D打印出的日志
2
能否实现在rt_thread系统运行中console的log输出实现切换串口
3
我想问问怎么修改日志的串口(LOG)?
4
menuocnfig中无法找到logmgr/ulog_file组件
5
关于Xshell 5的 问题
6
udisk.c文件log输出给格式不统一的问题。
7
RT-Thread使能C++特性后LOG()无法输出浮点数?
8
控制台串口如何输入信息
9
RTT的LOG为啥有时候能换行有时候又不换行
10
将RTT的log输出保存到了文件里,请问怎么这些文件打包压缩
推荐文章
1
RT-Thread应用项目汇总
2
玩转RT-Thread系列教程
3
国产MCU移植系列教程汇总,欢迎查看!
4
机器人操作系统 (ROS2) 和 RT-Thread 通信
5
五分钟玩转RT-Thread新社区
6
【技术三千问】之《玩转ART-Pi》,看这篇就够了!干货汇总
7
关于STM32H7开发板上使用SDIO接口驱动SD卡挂载文件系统的问题总结
8
STM32的“GPU”——DMA2D实例详解
9
RT-Thread隐藏的宝藏之completion
10
【ART-PI】RT-Thread 开启RTC 与 Alarm组件
最新文章
1
开源共生 商业共赢 | RT-Thread 2024开发者大会议程正式发布!
2
【24嵌入式设计大赛】基于RT-Thread星火一号的智慧家居系统
3
RT-Thread EtherKit开源以太网硬件正式发布
4
如何在master上的BSP中添加配置yml文件
5
使用百度AI助手辅助编写一个rt-thread下的ONVIF设备发现功能的功能代码
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
FinSH
ART-Pi
USB
DMA
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
FAL
rt-smart
ESP8266
I2C_IIC
WIZnet_W5500
UART
ota在线升级
PWM
cubemx
freemodbus
flash
packages_软件包
BSP
潘多拉开发板_Pandora
定时器
ADC
GD32
flashDB
socket
中断
Debug
编译报错
msh
SFUD
rt_mq_消息队列_msg_queue
keil_MDK
ulog
MicroPython
C++_cpp
本月问答贡献
a1012112796
20
个答案
3
次被采纳
张世争
11
个答案
3
次被采纳
踩姑娘的小蘑菇
7
个答案
3
次被采纳
rv666
9
个答案
2
次被采纳
用户名由3_15位
13
个答案
1
次被采纳
本月文章贡献
程序员阿伟
9
篇文章
2
次点赞
hhart
3
篇文章
4
次点赞
RTT_逍遥
1
篇文章
6
次点赞
大龄码农
1
篇文章
5
次点赞
ThinkCode
1
篇文章
1
次点赞
回到
顶部
发布
问题
分享
好友
手机
浏览
扫码手机浏览
投诉
建议
回到
底部