首先聊一聊全局變量:
在慕課上學習浙大老師的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(0, 0, 1, 0, OS_OPT_TIME_HMSM_STRICT, &err); Seconds++; if(Seconds > 59) { Seconds = 0; Minutes++; if(Minutes > 59) { Minutes = 0; Hours++; } if(Hours > 23) { Hours = 0; } } } }
假如在模塊執行完Minutes = 0;這一行代碼時,一個中斷發生了,並使得一個具有比void TimeOfDay(void *p_arg)更高優先級的任務進入了就緒表,那么在中斷結束返回后,TimeOfDay()就會被這個更高優先級的任務搶占而無法繼續運行。一旦高優先級的任務想要從時鍾模塊中獲取時間,那么由於中斷前時鍾模塊的小時值沒有更新,那么所讀到的將會是一個與正確時間相差整整一個小時的錯誤值。
這里的時鍾模塊就是一個共享資源,在ucos中必須對此加以保護,保證對共享資源的獨占訪問。
PS:以上ucos部分的內容皆來自於《嵌入式實時操作系統uc/OS-III》一書的第十三章