嵌入式C中由printf引起的"不可调试"bug

2019-07-13 07:35发布

1 bug发生

在工作中,基于以前的代码框架开发一个新的功能,在IMX6开发板使用嵌入式C开发。
由于逻辑稍稍复杂,于是在编写代码时,if else 的每一个分支都加了printf打印相关变量。这样做原因有两个:
  • 列表内容
  • 列表内容
方便查看变量
跟踪记录分支情况,便于判断程序是不是按照自己的逻辑在运行 然后,功能调出来了,初步测试也OK。
但是当疲劳测试时,会偶尔出现这种bug:
  • 首先发现原因是通信模块断连,至少该线程崩溃或挂起
  • 查看进程,发现还在运行,CPU占用率时与正常状态无异

2 bug”无法定位”

调试方法:
  • gdb + 断点调试
  • 打印log日志
先说第一种,网上各种找资料,各种敲命令。还麻烦同事帮忙用eclipse配置gdb+断点来调试,奈何就是无法定位到是哪一个线程出现问题。怀疑是某一线程进入死循环,占用其他线程的CPU使用时间导致。当bug出现时,info threads只能发现一堆线程被挂起,还是无法找到具体哪一线程有问题。调试一天,无果。
然后第二种就是——手动的每个线程加上printf,共计28个线程以及10多个回调函数,通通加了printf。好嘛。加完之后,偶现的问题变成了必现,有时候刚刚开进程就会出现,快则几秒钟,慢则几分钟。按照设想,屏幕上应该只会不停的打印某一线程的信息,然后问题就定位到了,可奇怪的是,问题出现时,所有线程都停止打印了,像程序挂掉一样,然而查看时发现,还在正常运行。难道是漏加了printf?还是说有其他的线程在默默跑?打印也没有,断点也不行,这还怎么调试?

3 printf”罪魁祸首”

如果关掉所有打印问题会不会再次变成偶发?如果偶发说明printf本身就存在问题吗?
顺着这个思路,再次调试,发现运行2小时还在正常跑,在此期间,也在CSDN的博客上看到,printf在多线程中并不安全。而有一篇更是详细解释了一下:
荐读:
printf()为什么有重入和性能上的问题
文章的核心观点:
如果中断发生的时候,当运行到printf的时候,假设发生了中断嵌套,而此时stdout资源被占用,所以第二个中断printf等待第一个中断的stdout资源释放,第一个中断等待第二个中断返回,造成了死锁