信號(hào)
提供異步時(shí)間處理方式
觸發(fā)時(shí)機(jī):
1.終端命令
2.硬件異常,由kernel拋向?qū)?yīng)的Process
3.kill函數(shù)/kill命令(超級(jí)用戶(hù)or Process的user相同,這里的user id一般是指實(shí)際用戶(hù)ID or 有效用戶(hù)ID,如果支持 _POSIX_SAVED_IDS,那么檢查saved-user-id)
4.軟件觸發(fā)(滿(mǎn)足信號(hào)條件)
這里也稍微解釋下Kill這個(gè)東西,kill函數(shù),kill命令并不是字面上殺掉某些東西,kill只是在特定的時(shí)間發(fā)送信號(hào),
具體的處理取決于信號(hào)本身和信號(hào)的處理方式。
信號(hào)的處理方式:
這個(gè)有點(diǎn)類(lèi)似Java Exception的處理方式,catch住or往上throw
APUE講的信號(hào)處理方式有三種
1.忽略,SIGKILL/SIGSTOP不能忽略;一般如果Process自己不管的話(huà),應(yīng)該會(huì)走到系統(tǒng)默認(rèn)的處理流程中,所以不能忽略這件事情是系統(tǒng)自己就會(huì)保證的。
2.捕捉信號(hào),例如SIGCHLD,一般parent會(huì)call waitpid取子進(jìn)程終止?fàn)顟B(tài),避免他處理Zombie狀態(tài)。
3.執(zhí)行系統(tǒng)默認(rèn)動(dòng)作
我感覺(jué)1和3可以歸為一類(lèi)吧,只是有些signal沒(méi)有系統(tǒng)默認(rèn)動(dòng)作,然后就跳過(guò)去了。一般的系統(tǒng)默認(rèn)動(dòng)作也就是終止進(jìn)程。
SIGKILL/SIGSTOP不能被忽略的原因我覺(jué)得講的不錯(cuò),提供超級(jí)用戶(hù)終止進(jìn)程的可靠方法,不然后續(xù)有可能進(jìn)程的行為是未定義的.
signal函數(shù)定義:(
void (*signal(int signo, void(*func)(int)))(int);
這個(gè)C函數(shù)的聲明有點(diǎn)難看懂
APUE講signal的語(yǔ)義與實(shí)現(xiàn)有關(guān),所以建議大家都用sigaction
不過(guò)我看了下Android Bionic下的實(shí)現(xiàn),分別包含BSD以及SYSV的版本,但也都變成了sigaction,所以一般在C庫(kù)中就保證了這一點(diǎn),也就無(wú)所謂了。





























exec函數(shù)會(huì)講信號(hào)處理方式還原為系統(tǒng)默認(rèn),這個(gè)應(yīng)該毫無(wú)疑問(wèn),exec后地址空間就不一樣了,保留之前的捕捉函數(shù)也是無(wú)意義的;在這之前是有意義的,我的意思是說(shuō)fork后exec之前。
后面有列一大堆是否可以重入的函數(shù),不太想記,然后講到了malloc
我想不能重入的函數(shù)無(wú)外乎兩種類(lèi)型
one: 自己有maintain一些全局or static變量 --> malloc 維護(hù)分配內(nèi)存時(shí)static heap linklist
two: 函數(shù)參數(shù)里面有引用之類(lèi)的,會(huì)影響調(diào)用者的情況。
然后我看到這個(gè)立馬就想到了線程安全,malloc是線程安全的麼?
去看了下Bionic的實(shí)現(xiàn),然后就又看到下面這個(gè)名字 Dong Lea,馬上就會(huì)想到Java Concurrent庫(kù),看到這個(gè)你直接就會(huì)有想法,Bionic里面這個(gè)malloc肯定是線程安全的;
有時(shí)候被這些東西搞的很累,比較煩他,而且Bionic里面用的malloc的那個(gè)實(shí)現(xiàn)版本(aka dlmalloc)我又沒(méi)看懂:(,只好去網(wǎng)上search了一下,有個(gè)人做過(guò)實(shí)驗(yàn),有些結(jié)論還是可以參考的
http://www.360doc.com/content/12/0420/23/168576_205320609.shtml
總的來(lái)說(shuō),這個(gè)東西取決于C庫(kù)實(shí)現(xiàn),我想Bionic和Glibc都應(yīng)該一樣會(huì)支持兩種不同的版本,然后編譯的時(shí)候就可以確定是否有線程相關(guān)操作,然后在link的時(shí)候link過(guò)來(lái)不同的版本
線程安全和信號(hào)安全是兩個(gè)概念
如果在線程安全的malloc中,信號(hào)處理函數(shù)中發(fā)生重入,那么應(yīng)該是會(huì)發(fā)生dead lock
如果是非線程安全中,那么應(yīng)該是所謂的 undefined behavior.
前面還有一個(gè)概率忘記寫(xiě)
早期的Unix系統(tǒng),如果系統(tǒng)在執(zhí)行一個(gè)低速系統(tǒng)調(diào)用(基本可以總結(jié)為blocking IO:包括IPC,F(xiàn)ile IO,ioctl),那么如果捕捉到信號(hào),那么系統(tǒng)就會(huì)中斷這個(gè)system call -->EINTR, 這在當(dāng)時(shí)是有理由的,而且理由看起來(lái)也合理,但是由于user有時(shí)候并不知道某些系統(tǒng)調(diào)用是否是低速系統(tǒng)調(diào)用,BSD引進(jìn)了自動(dòng)重啟的功能,linux follow這種規(guī)則
然后有幾個(gè)版本的signal函數(shù)
signal默認(rèn)自動(dòng)重啟
_signal(signum, handler, SA_RESTART) 這是由于在sigaction中的flag為SA_RESTART,上面sysV的實(shí)現(xiàn)我不想多寫(xiě)了。
sigaction也就是可選的了。
但一般我印象中好多 read/write都是會(huì)自己判斷返回值以及errno 是否為 EINTR,然后retry,因?yàn)樯厦孢@種方式依賴(lài)系統(tǒng)實(shí)現(xiàn),需要將所有的signal都設(shè)定為SA_RESTART,那么如果有某個(gè)信號(hào)發(fā)生的時(shí)候,被他INTR的系統(tǒng)調(diào)用才會(huì)自動(dòng)重啟,不知道默認(rèn)signal在注冊(cè)處理行為的時(shí)候是不是如此,感覺(jué)不太好用。
alarm函數(shù)
對(duì)于很多像alarm這種函數(shù),在設(shè)計(jì)時(shí)or使用時(shí)均應(yīng)該考慮臨界值的問(wèn)題
alarm的唯一性,是by process的,process單例
所以如果alarm兩次,那么第一次會(huì)被覆蓋,怎么處理第一次未完成的情況->返回值會(huì)帶回來(lái)剩余的時(shí)間
怎么取消設(shè)定的alarm
傳入值為0 means cancel
總之了,這個(gè)東西設(shè)計(jì)的時(shí)候還蠻完善的
后面還有一堆有關(guān)signal的標(biāo)準(zhǔn)函數(shù),這里也就不一一列舉
作業(yè):
1.去掉for(;;), 那捕捉到SIGUSR1就返回了,pause()只要捕捉到信號(hào),等信號(hào)處理完時(shí)自己就會(huì)返回并帶回EINTR。不曉得為啥有這種題目...
2.實(shí)現(xiàn)sig2str,這有點(diǎn)無(wú)聊了.:(不寫(xiě)
3.畫(huà)runtime stack的樣子。
4.IO操作的超時(shí)最好不要采用alarm的方式,各種原子問(wèn)題,select/poll是最好的選擇。
后面有好一些是要寫(xiě)代碼的...
我略想,然后就不太愿意寫(xiě)了.
PS:有些東西略難...我也是有點(diǎn)想不清楚的樣子,打算慢慢搞。
后面決定把標(biāo)題改一下,順利看完書(shū)吧...Orz.