[信息] 【实战经验】多任务系统中的不可重函数使用注意事项

[复制链接]
2025|5
 楼主| 香水城 发表于 2015-12-25 15:11 | 显示全部楼层 |阅读模式
本帖最后由 香水城 于 2017-8-16 14:31 编辑

多任务系统中的不可重函数使用注意事项
前言
本**主要介绍多任务系统中的的不可重入函数的用法和如何避免出错。

1. 可重入函数与不可重入函数的区别
在多任务环境中,可重入函数可以由多于一个的任务并发使用,而不用担心数据错误。这个函数可以在执行的任何时刻中断
它。
不可重入函数由于使用了一些系统资源,比如全局变量等,不能被很多任务所共享,除非能确保函数的互斥性。
1)可重入函数:
不返回指向静态数据的指针。
使用本地数据。
如果必须访问全局变量,记住利用互斥信号量来保护全局变量。
绝不调用任何不可重入函数。
3)不可重入函数:
函数中使用了静态变量。
函数返回静态变量。
函数中调用了不可重入函数。
函数体内使用了静态的数据结构;
函数体内调用了malloc()或者free()函数;
函数体内调用了其他标准I/O 函数。
总的来说,如果一个函数在重入条件下使用了未受保护的共享的资源,那么它是不可重入的。

2. 不可重入函数的一次错误应用示例,造成I2C Master 端收到的数据无**确解析。
这个产品使用的MCU 为STM32F411,是作为Sensor hub使用的,做为I2C 的Master端,总线上挂了好几个传感
器,如加速度、陀螺仪、光感应等。并且同时采用定时方式和中断方式通过I2C总线读取sensor上数据的。
1.PNG
客户产品功能是在实时操作系统上实现的,属于多任务系统。在中断处理函数中会调用I2C_Read(…)函数,而
I2C_Read(…)函数中又调用了 HAL_I2C_Master_Receive_IT(…)函数。
函数代码在示例程序中的位置如下:
…\stm32cubef4\STM32Cube_FW_F4_V1.6.0\Drivers\STM32F4xx_HAL_Driver\Src 的stm32f4xx_hal_i2c.c
stm32f4xx_hal_i2c.c 文件中有一段I2C slave 接收程序,具体代码如下:
2.PNG
3.PNG
4.PNG
上面程序中通过下面指令对硬件端口进行加锁:
__HAL_LOCK(hi2c);
__HAL_UNLOCK(hi2c);
初步看来多任务系统中好像是安全的,但实际应用中并非如此(客户的不可重入函数调用了这个I2C 函数),下面用图例来说明:
5.PNG
上图中”t”为时间轴,”T1”时间发生 sensor 1 中断并调用I2C_Read(…),在I2C_Read(…)函数中会调用
HAL_I2C_Master_Receive_IT(…)函数,在调用HAL_I2C_Master_Receive_IT(…)函数之前已经进行了传参,即:
Addr=0x1A0,Size=3,Buf 指向buffer1 的地址。
当程序运行到”T2”时又来了一个sensor 2 中断,调用I2C_Read(…)函数,在调用HAL_I2C_Master_Receive_IT(…)函数
之前已经传参完成。此时的I2C 地址,Size 等的值如下:
Addr=0x1B0,Size=5,Buf 指向buffer1 的地址。
由于HAL_I2C_Master_Receive_IT(…)程序有加锁,和判断busy 状况,当程序判断到总线busy 时或是有加锁时跳出
HAL_I2C_Master_Receive_IT(…)函数;但此时的I2C 地址,buffer 地址, Size 都已经是Sensor2 对应的值了。然后程序
进入 ”T3“。
Sensor2 中断返回时会把sensor2 的Size 值5 赋给hi2c->XferSize,因此后面的I2C 通讯中的值如下:
Addr=0x1A0(sensor1 value)
Buf 指向buffer1(sensor1 value)Size=5(sensor2 value)
因此程序处理中会出错。

3.上面的问题解决方法:
上面多任务系统的I2C 处理程序中出现了不可重入函数的多次调用问题,主要是I2C_Read(…)为不可重入函数,但对它进行
了多次调用,使变量更改。
下面的办法可以解决多次调用问题,既对调用I2C_Read(…)的动作加锁,使第二个I2C 中断发生后不进行传参动作,如下图所示:
6.PNG
也可以使用信号量方式处理。如下图:
7.PNG

4. 程序占用资源后要防止死锁发生
上面I2C 程序处理中要注意不要发生死锁,假设在I2C_Read(…) 函数里有一条指令是对I2C 端口的状态进行判断,如busy
状态,如果程序一直在等待中,就很容易发生死锁,下面图示是程序发生死锁的情况:
8.PNG
在上面程序中需要增加超时跳出机制来防止死锁。

5.总结
在多任务系统中,在使用函数时要了解函数的可重入性,对待有信号量或是加互斥锁的函数要防止死锁的发生。通讯程序比
如I2C, UART 等最好增加超时跳出机制。

对应PDF:多任务系统中的不可重函数使用注意事项
更多实战经验请看:【ST MCU实战经验汇总贴】


airwill 发表于 2015-12-25 19:37 | 显示全部楼层
造成I2C Master 端收发的数据错误, 这是软件设计问题, 不合适算作不可重入函数问题
应该将 I2C 作为单独的设备做成设备驱动接口与任务通信.

评论

正解。  发表于 2015-12-26 00:55
yiyigirl2014 发表于 2015-12-25 22:24 | 显示全部楼层
在多任务系统中,在使用函数时要了解函数的可重入性,对待有信号量或是加互斥锁的函数要防止死锁的发生。通讯程序比如I2C, UART 等最好增加超时跳出机制。原来这样啊
karaxiaoyu 发表于 2015-12-25 23:57 | 显示全部楼层
学习了
wangjianxing 发表于 2015-12-26 09:43 | 显示全部楼层
感谢楼主分享资源
您需要登录后才可以回帖 登录 | 注册

本版积分规则

认证:意法半导体(中国)投资有限公司
简介:STM32技术专家

596

主题

17195

帖子

291

粉丝
快速回复 在线客服 返回列表 返回顶部