乙個函式被多個執行流呼叫,有可能在第一次呼叫還沒返回時就再次進入函式,稱為重入。
例如上面的insert函式,在執行第一步時收到訊號產生硬體中斷,轉去訊號處理函式,而訊號處理函恰好呼叫了insert函式,由於兩個函式操縱了同乙個鍊錶而產生意外的結果,所以這個函式是不可重入函式。如果這個函式只是操縱自己的區域性變數就是可重入的。
另外呼叫io庫,或者使用malloc的函式也是不可重入的。
學c語言的時候知道volatile可以禁止編譯器優化,始終從記憶體裡拿變數的資料,在訊號裡它又有什麼作用?
int flag = 0;
void handler()
int main()
printf(".\n");
sleep(1);}}
按理說睡三秒後,應該停止打點。但是如果加入優化,編譯器在main控制流裡看不到flag的改變,可能會從暫存器裡拿flag,而捕捉訊號後即使改變了flag,系統也不知道。
如果用volatile修飾flag,就能消除這種影響。
//設定鬧鐘
alarm(s);
pause();
這其實就要求著我們以新的視角去審視**,這樣的與**時序緊密相關的錯誤稱為竟態條件。
如果在掛起程序之前遮蔽alrm訊號能不能解決問題呢?
//遮蔽alrm
alarm(s);
//解除遮蔽alrm
pause();
看樣子在pause之前不會遞達alrm訊號了。其實解除遮蔽這一步和pause還是有竟態條件的問題,萬一在解除遮蔽後被中斷了。
真正的解決辦法是把解除訊號遮蔽和掛起設為原子操作!即使cpu中斷也不能分離他倆。
int sigsuspend(const sigset_t *sigmask)
sigsuspend就是這麼乙個函式
sigset_t newmask, oldmask, suspmask;
//註冊alrm訊號
//遮蔽alrm訊號
alarm(s);
//解除遮蔽並掛起
suspmask = oldmask;
sigdelset(&suspmask, sigalrm);//確保alrm沒有被遮蔽
sigsuspend(&suspmask);//遞達任意訊號後喚醒
如果父程序在子程序之前終止,那麼子程序變為孤兒程序,因此父程序需要wait來**子程序,但是wait以後父程序阻塞,不能幹別的事情,有沒有辦法讓父程序幹自己的事,子程序退出時自動**?
有,子程序在退出時會給父程序發sigchld訊號,利用這個訊號可以讓父程序捕捉處理。
void handler(int signo)
}int main()
while(1)
}
waitpid:
當正常返回的時候,waitpid返**集到的子程序的程序id;
如果設定了選項wnohang,而呼叫中waitpid發現沒有已退出的子程序可收集,則返回0;
LInux 的併發和竟態 中斷 原子操作 自旋鎖
併發是指的是多個執行單元同時被執行,而併發的執行單元對共享資源 硬體資源和軟體上的全域性變數 靜態變數等 的訪問很容易導致竟態。主要有以下三個方面 一 對稱處理器的多個cpu。二 單cpu內,程序與搶占它的程序 三 中斷可能被其他的程序中斷。而這個正是我們的重點。而防止中斷的的方法主要是 1 遮蔽中...
linux作業系統之競態條件(時序競態)
1 時序競態 前後兩次執行同乙個程式,出現的結果不同。2 pause函式 使用該函式會造成程序主動掛起,並等待訊號喚醒,呼叫該系統呼叫的程序會處於阻塞狀態 主動放棄cpu 函式原型 int pause void 返回值為 1,並設定errno為eintr 使用pause和alarm實現sleep函式...
Linux使用者態和核心態
一 unix linux的體系架構 如上圖所示,從巨集觀上來看,linux作業系統的體系架構分為使用者態和核心態 或者使用者空間和核心 核心從本質上看是一種軟體 控制計算機的硬體資源,並提供上層應用程式執行的環境。使用者態即上層應用程式的活動空間,應用程式的執行必須依託於核心提供的資源,包括cpu資...