一、信號使用基礎知識
1.信號的發(fā)送與捕捉:
同步:
多個進程協(xié)同完成一件事情,當資源不可用時,其他的進程阻塞等待,類比流水線操作,一步一步有先后地完成一個產(chǎn)品。
異步:
多個進程做多項任務,同時運行,互不干擾,當需要建立聯(lián)系的時候,停止運行,建立聯(lián)系,處理數(shù)據(jù),處理完成繼續(xù)各自運行。異步多個進程或線程獨自運行,效率較高,系統(tǒng)的實時性用中斷實現(xiàn)。
信號:
內核和用戶空間溝通的信使。直接進行用戶空間進程和內核進程之間的交互,內核進程也可以利用它來通知用戶空間進程發(fā)生了哪些系統(tǒng)事件。
eg:
進程結束時,內核會發(fā)送一個SIGCHLD信號以通知父進程子進程結束。內核向用戶發(fā)送信號時,用戶進程可以進程阻塞。就像項目不能因為一個無名信號出錯而結束進程。
________________________________________
2.信號的周期:
紅色中的的內容都是內核操作,與用戶程序無關,用戶程序就是信號處理。
信號由內核產(chǎn)生,要由用戶空間進行注冊和注銷。信號處理是定義的處理方式,相當于內核到用戶的一次切換。
用戶的處理方式有三種:
1)忽略
不理踩,有兩個信號不可以忽略(KILL和STOP信號);
2)捕捉
捕捉信號后,自定義處理方式,(用signal()進行注冊);
3)默認
系統(tǒng)默認處理方式。
________________________________________
3.信號處理流程:
PS:
實際執(zhí)行信號的處理動作稱為信號投遞(Delivery),信號從發(fā)生到投遞之間的狀態(tài),稱為信號未決(Pending)。
進程可以選擇阻塞(Block)某個信號。被阻塞的信號產(chǎn)生后將保持在未決狀態(tài),直到進程解除對此信號的阻塞,才執(zhí)行投遞的動作。
每個信號都有兩個標志位分別表示阻塞和未決,還有一個函數(shù)指針表示處理動作。
信號產(chǎn)生時,內核在進程控制塊中設置該信號的未決標志(表示某信號是否發(fā)生過),直到信號投遞完畢才清除該標志。在上圖的例子中,
1. SIGHUP信號未阻塞也未產(chǎn)生過,當它遞達時執(zhí)行默認處理動作。
2. SIGINT信號產(chǎn)生過,但正在被阻塞,所以暫時不能投遞。雖然它的處理動作是忽略,但在沒有解除阻塞之前不能忽略這個信號,因為進程仍有機會改變處理動作之后再解除阻塞。
3. SIGQUIT信號未產(chǎn)生過,一旦產(chǎn)生SIGQUIT信號將被阻塞,它的處理動作是用戶自定義函數(shù)sighandler。
未決和阻塞標志可以用相同的數(shù)據(jù)類型sigset_t來存儲,sigset_t稱為信號集,這個類型可以表示每個信號的“有效”或“無效”狀態(tài),在阻塞信號集中“有效”和“無效”的含義是該信號是否被阻塞,而在未決信號集中“有效”和“無效”的含義是該信號是否處于未決狀態(tài)。
________________________________________
4.信號應用的場合:
________________________________________
5.常用的幾種信號與默認方式:
SIGALRM定時信號,定時N秒,時間到,發(fā)送一個鬧鐘信號,終止進程。
對信號的處理方式解釋:
1)忽略此信號
除了兩種信號(SIGKILL和SIGSTOP)不能被忽略外,其它的的信號都可被忽略,這兩個信號不能被忽略的原因是:它們提供一種終極的終止或停止進程的可靠方法,這是一種終極裁判權,如果這兩個信號都被忽略了的話,某個進程跑飛后就沒有辦法終止或停止這個進程。
另外忽略某些硬件產(chǎn)生的信號被認為是不可取的,如我們如果忽略非法存儲訪問或除以0等硬件產(chǎn)生的信號的話,進程狀態(tài)未定義的(無法確定的狀態(tài))。
2)捕獲信號
如果某個進程被通知某個信號發(fā)生了,但是想要捕獲這個信號的話,該進程就必須向內核注冊一個捕獲函數(shù),當相應的信號發(fā)生時,捕獲函數(shù)就會被調用并執(zhí)行希望對這個事件的處理。
3)執(zhí)行系統(tǒng)的默認操作
其實我們內核為每個信號在發(fā)生時都規(guī)定了一個默認的操作,如果我們不捕獲也不忽略的話,當這個信號發(fā)生時,進程會按照默認方式去處理這些發(fā)生的信號,當然對于絕大多數(shù)信號而言,其默認的處理方式都是終止接收到該信號的進程或者忽略此信號。
/**************************************************************************拓展:
查看信號的方法:
kill -l 或man 7 signal
通常有62以上,kill -l 列出的前面32個是非實時的,signal函數(shù)只能使用前( 1 -- 31),后面為拓展信號,signal不能用,中間缺少的沒有編號。前面(1 -- 31)是非實時的,信號不支持排隊,可能造成信號丟失。有預定義的含義和處理方式函數(shù)。后面的實時信號支持排隊
各種信號說明:
//www.2cto.com/os/201608/537204.html (感謝博主詳細列出了各種信號)
***************************************************************************/
我們常用的有:
INT, QUIT, KILL, USR1, USR2 ALRM STOP TERM .
USR1,和USR2在硬件中沒有任何價值,在應用程序中,可以使用usr1和usr2進行自定義通信。
TTOU/TTIN網(wǎng)絡開發(fā)中常用的信號,IO信號在網(wǎng)路常用。
________________________________________
二、相關系統(tǒng)調用:
1.kill()和raise()
pid = -1,向所有進程發(fā)送信號(除了init進程)。
sig = 0;表示只檢查錯誤信息,不發(fā)送信號。沒有0號編號信號。
kill示例:
raise示例:
當前進程進入stop態(tài),發(fā)送CONT信號繼續(xù)運行。如果發(fā)送的是USR1信號,默認進程退出。
________________________________________
2.a(chǎn)larm()和pause()
0.alarm是指定一定時間后發(fā)送信號。
1.要注意的是,一個進程只能有一個鬧鐘時間。如果在調用alarm時已設置過鬧鐘時間,則之前的鬧鐘時間被新值所代替。
2.alarm函數(shù)只設置時鐘,設置完成后,程序向下繼續(xù)運行。(補充說明alarm函數(shù)只是設置定時鬧鐘,并不阻塞);
3.等待信號來臨可以利用while檢測等待或利用pause函數(shù)將進程掛起。
pause()接收任意信號就會結束掛起。
示例代碼: myalarm.c
mypause.c
利用alarm和pause實現(xiàn)sleep功能:
補充:
alarm()和sleep()函數(shù)不同,alarm信號并不會阻塞,相當于訂了鬧鐘后,系統(tǒng)在后臺計時,到了指定時間就會發(fā)送ALRM信號;sleep()函數(shù)會使進程進入睡眠態(tài),進程暫停執(zhí)行,直到時間結束。
华清图书馆
0元电子书,限时免费申领10本华清图书PDF版
扫码关注华清远见公众号