linux系統(tǒng)編程之基礎必備(六):可重入函數(shù)、sig
是編譯器優(yōu)化得有錯誤嗎?不是的。設想一下,如果程序只有單一的執(zhí)行流程,只要當前執(zhí)行流程沒有改變a的值,a的值就沒有理由會變,不需要反復從內存讀取,因此上面的兩條指令和while(!a);循環(huán)是等價的,并且優(yōu)化之后省去了每次循環(huán)讀內存的操作,效率非常高。
所以不能說編譯器做錯了,只能說編譯器無法識別程序中存在多個執(zhí)行流程。之所以程序中存在多個執(zhí)行流程,是因為調用了特定平臺上的特定庫函數(shù),比如sigaction、pthread_create,這些不是C語言本身的規(guī)范,不歸編譯器管,程序員應該自己處理這些問題。
C語言提供了volatile限定符,如果將上述變量定義為volatile sig_atomic_t a=0;那么即使指定了優(yōu)化選項,編譯器也不會優(yōu)化掉對變量a內存單元的讀寫。
對于程序中存在多個執(zhí)行流程訪問同一全局變量的情況,volatile限定符是必要的,此外,雖然程序只有單一的執(zhí)行流程,但是變量屬于以下情況之一的,也需要volatile限定:
變量的內存單元中的數(shù)據(jù)不需要寫操作就可以自己發(fā)生變化,每次讀上來的值都可能不一樣;
即使多次向變量的內存單元中寫數(shù)據(jù),只寫不讀,也并不是在做無用功,而是有特殊意義的;
什么樣的內存單元會具有這樣的特性呢?肯定不是普通的內存,而是映射到內存地址空間的硬件寄存器,例如串口的
接收寄存器屬于上述第一種情況,而發(fā)送寄存器屬于上述第二種情況。
sig_atomic_t類型的變量應該總是加上volatile限定符,因為要使用sig_atomic_t類型的理由也正是
要加volatile限定符的理由。
對于多線程的程序,訪問沖突的問題是很普遍的,解決的辦法是引入鎖,獲得鎖的線程可以完成“讀-修改-寫”的操作,然后釋放鎖給其它線程,沒有獲得鎖的線程只能等待而不能訪問共享數(shù)據(jù),這樣“讀-修改-寫”三步操作組成一個原子操作,要么都執(zhí)行,要么都不執(zhí)行,不會執(zhí)行到中間被打斷,也不會在其它處理器上并行做這個操作。
評論