Linux 竟態條件和SIGCHLD

2021-08-20 15:31:04 字數 1674 閱讀 6627

乙個函式被多個執行流呼叫,有可能在第一次呼叫還沒返回時就再次進入函式,稱為重入。

例如上面的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資...