0%

可重入与不可重入

起因

为什么突然想起来这个属性呢,因为最近在看嵌入式系统设计的课程。看到抢占式系统不能直接使用不可重入函数,一下子我就茅塞顿开了。

什么是可重入和不可重入

你可以认为就是该函数是否独立,是否是模块化的!
如下:

1
2
3
4
5
6
7
8
9
volatile uint32_t staticData = 100;

uint32_t testFun()
{
if(staticData>=101)
return 0;

return staticData++;
}

由上面函数可以发现,第一次调用的时候是可以正常返回staticData的数据的,但是以后的调用都是返回0,也就是无效的,因为它使用全局的静态变量,所以它是非独立的。假如我任务一是低优先级,此时调用这个函数,但是任务二立刻发生了抢占但是也调用了这个函数,那么任务二是正常调用并得到了数据,此时回到任务一调用就得到了0,是无效的。这个时候,彼此之间发生了干扰,这是不合理的!对系统的稳定和安全有大问题,尤其是项目大的时候。

如何分辨是否是可重入

1.是否调用全局变量,注意了还有类中的static变量也是全局变量
2.是否有内部的static变量
3.是否发生了跳转 如setjmp和longjmp
4.是否有调用了malloc和new的变量
5.是否有标准 I/O 函数

note:传参导致的函数返回错误值,这不算不可重入函数,这是你因为外部原因导致数据错误。函数只是正常的反馈数据错误,此时是合理正确的。不要搞混了!!!

如何避免或者解决带来的问题

1.一个不可重入函数,只给一个任务来使用
2.减少不可重入函数的定义,选择使用传参来进行判断和数据处理,这样就可以在任务进行判断,而并非来自函数来进行判断,这样就减少不可预知的错误
3.多个标志位来做标记,比如上面的任务二使用之后,就在一个自定义的系统属性结构体中进行使用过的痕迹(标志位)标记,然后在不可重入函数中进行判断和处理等,非常繁琐,别用。

结语

OS是非常考验设计师和工程师的水准的,对于每个资源的调度和处理,每一个流程都要了如指掌才行,得知道这样得代价是什么,很多时候,其实我们都不会犯错误。因为,这些技术和知识,其实就在我们的日常习惯中,大家都不会乱用goto,都不会乱使用一些繁琐的东西,大家都知道这样不好。所以很多时候,没出现错误和bug!但是出现错误了,记得总结为什么出错了,才能真正有效的进步。不要把习惯当成标准!你只是一时的好习惯拯救了自己,但是你却是在不经意和没有思考之中调用了自己的固有思维罢了。

-------------下次的来访是什么时候呢[doge]-------------