首先聊一聊全局变量:
在慕课上学习浙大老师的C语言课程的时候,翁恺老师一直在强调在程序中我们要避免使用全局变量,C语言的程序员(尤其像我这样的野生程序员)为了方便,经常会不顾这个编码规范。全局变量有一些显而易见的好处:全局可见,内存地址固定,读写效率高。比起优点来,全局变量的槽点更多:1)学过面向对象语言的同学会更加谨慎的使用全局变量,这破坏了函数的封装性能,降低了函数的可移植性。2)使代码可读性差,大型程序里面简直是灾难 3)生存期长,会占用较多的内存单元。
最近在看一本书叫《信息系统设计与分析》,里面从软件工程的角度也阐述了全局变量的危害。优秀的软件设计应尽可能达到高内聚低耦合。
内聚是指一个模块各个元素间彼此结合的紧密程度。
耦合是指模块之间互相连接的紧密程序。(关于这个话题,可以看一下其他博主的博文)全局变量毫无疑问会增加系统的耦合度。因此,这也是我们慎用全局变量的理由
ucos中需要注意的全局变量:
从裸机到ucos需要深刻转换的一点是ucos是一个可剥夺型的多任务内核,这意味着ucos总是执行当前优先级最高的就绪任务。全局变量生存期从程序执行到结尾,作用域是从变量定义开始到源文件结束。这意味着在ucos这样的可剥夺式的系统中,必须保障对全局变量的独占式访问。否则,有可能会出现任务间的竞争和数据破坏。
在《嵌入式实时操作系统ucos3》中举了一个关于时间更新的例子很有力的说明了全局变量在任务切换时不做保护带来的隐患:
u8 Seconds;
u8 Minutes;
u8 Hours;
void TimeOfDay(void *p_arg)
{
(void)p_arg;
OS_ERR err; while (DEF_TRUE) { /* Task body, always written as an infinite loop. */ OSTimeDlyHMSM(, , , ,
OS_OPT_TIME_HMSM_STRICT,
&err);
Seconds++;
if(Seconds > )
{
Seconds = ;
Minutes++;
if(Minutes > )
{
Minutes = ;
Hours++;
}
if(Hours > )
{
Hours = ;
}
}
}
}
假如在模块执行完Minutes = 0;这一行代码时,一个中断发生了,并使得一个具有比void TimeOfDay(void *p_arg)更高优先级的任务进入了就绪表,那么在中断结束返回后,TimeOfDay()就会被这个更高优先级的任务抢占而无法继续运行。一旦高优先级的任务想要从时钟模块中获取时间,那么由于中断前时钟模块的小时值没有更新,那么所读到的将会是一个与正确时间相差整整一个小时的错误值。
这里的时钟模块就是一个共享资源,在ucos中必须对此加以保护,保证对共享资源的独占访问。
PS:以上ucos部分的内容皆来自于《嵌入式实时操作系统uc/OS-III》一书的第十三章