Unix信号处理一些笔记
為什么80%的碼農(nóng)都做不了架構(gòu)師?>>> ??
從信號(hào)到線程,然后再到線程中的信號(hào),再然后就是守護(hù)進(jìn)程中關(guān)于信號(hào)的一些個(gè)實(shí)例,一堆系統(tǒng)調(diào)用,有點(diǎn)迷茫,貌似又有一線線索在串起這些個(gè)知識(shí)點(diǎn),嗯,就先把這些知識(shí)點(diǎn)寫出來(lái),再總結(jié)吧。
1、進(jìn)程的信號(hào)屏蔽字:規(guī)定了進(jìn)程當(dāng)前要阻塞的信號(hào)集。
? ? ?sigprocmask調(diào)用就是設(shè)置當(dāng)前進(jìn)程的信號(hào)屏蔽字的,但要注意,該調(diào)用對(duì)基于線程的信號(hào)處理是無(wú)效的(后面將提及,pthread_sigmask調(diào)用才是針對(duì)線程的信號(hào)屏蔽字的設(shè)置)。
2、如果有信號(hào)被阻塞,也就是未決狀態(tài)的信號(hào),那么可以調(diào)用sigpending取得當(dāng)前所有的未決信號(hào)集,多次發(fā)生的信號(hào)會(huì)被認(rèn)為是發(fā)生了一次,并寫入sigpending傳入的參數(shù)指針指向的內(nèi)存中。注,這時(shí)這些信號(hào)仍舊是未決狀態(tài),sigpending所做的就是查詢一下當(dāng)前有哪些信號(hào)被block掉了。
3、有什么辦法可以臨時(shí)解除某些信號(hào)的屏蔽,并等待這些信號(hào)的發(fā)生,在這些信號(hào)發(fā)生后,調(diào)用進(jìn)程停止等待,繼續(xù)執(zhí)行,并恢復(fù)原先的信號(hào)屏蔽設(shè)置呢?有的,就是sigsuspend,該調(diào)用臨時(shí)設(shè)置參數(shù)指定屏蔽字為當(dāng)前進(jìn)程的信號(hào)屏蔽字,在捕捉到一個(gè)信號(hào)或者發(fā)生了一個(gè)會(huì)終止該進(jìn)程的信號(hào)之前,該進(jìn)程被掛起,如果捕捉到一個(gè)信號(hào)而且從該信號(hào)處理程序返回,則sigsuspend返回,并且將該進(jìn)程的信號(hào)屏蔽字設(shè)置為調(diào)用sigsuspend之前的值。
下面一個(gè)例子:
void sig_usr(int signo) {// do some things about signal }int main(int argc, char *argv[]) {sigset_t global_mask;sigset_t tmp_mask;if (SIG_ERR == signal(SIGUSR1, sig_usr)) {perror("signal error");exit(1);}// block all signalssigfillset(&global_mask);sigprocmask(SIG_BLOCK, &global_mask, NULL);// unblock SIGUSR1 temporarilysigfillset(&tmp_mask);sigdelset(&tmp_mask, SIGUSR1);sigsuspend(&tmp_mask);printf("after sigsuspend.....\n");return 0; }上面的例子的意思是,屏蔽所有的信號(hào),僅只處理SIGUSR1信號(hào)一次,注意,這里必須為SIGUSR1信號(hào)設(shè)置信號(hào)處理程序,否則,該程序就不會(huì)在sigsuspend之后返回了。sigsuspend一般都是用來(lái)做進(jìn)程同步用的,進(jìn)程間通過(guò)發(fā)送信號(hào)告訴對(duì)方它自己已經(jīng)準(zhǔn)備好了,常常是接收信號(hào)的一方要等待對(duì)方的信號(hào),所以一般都會(huì)使用sigsuspend來(lái)等待。但是要注意了,在等待這些信號(hào)之前,就必須要先把這些信號(hào)屏蔽了,否則就會(huì)產(chǎn)生一個(gè)時(shí)間窗口,在sigsuspend之前就錯(cuò)過(guò)了信號(hào)了(如果這個(gè)信號(hào)永遠(yuǎn)都不再發(fā)生,那么這個(gè)進(jìn)程就永遠(yuǎn)阻塞)。在APUE中有這樣的一個(gè)例子,就是進(jìn)程間的同步,在for之前就把信號(hào)屏蔽好了,然后再fork,各個(gè)子進(jìn)程然后再sigsuspend,這樣就會(huì)不錯(cuò)過(guò)信號(hào)了。
注意,以上所講述的調(diào)用,僅只針對(duì)進(jìn)程,而在線程中則無(wú)效的。
4、線程中關(guān)于信號(hào)的機(jī)制(建議看FreeBSD的manpages,Linux的manpages是Posix定義的,太TMD暈了)
(1)每個(gè)線程都有自己的信號(hào)屏蔽字,新被創(chuàng)建的線程繼承創(chuàng)建者線程的信號(hào)屏蔽字(副本),?他們須通過(guò)pthread_sigmask來(lái)設(shè)置自己的信號(hào)屏蔽字(包括main在內(nèi))。
(2)信號(hào)處理是進(jìn)程中所有線程共享的,也就是說(shuō),任何一個(gè)線程改變了信號(hào)的處理方法,都影響其它線程。如果信號(hào)與硬件故障或計(jì)時(shí)器超時(shí)相關(guān),該信號(hào)就被發(fā)送到引起該事件的線程中去。其它信號(hào)則被發(fā)送到任意一個(gè)線程(在Linux中,就是當(dāng)前進(jìn)程的第一個(gè)線程-_-|||)。
(3)在線程處理中,與sigsuspend(進(jìn)程)相似的調(diào)用是sigwait,但是它功能就強(qiáng)多了,語(yǔ)義上也有所不同,首先,它第一個(gè)參數(shù)的意思是要等待信號(hào)集(sigsuspend則是把第一個(gè)參數(shù)信號(hào)集臨時(shí)設(shè)為當(dāng)前進(jìn)程的信號(hào)屏蔽字,意思是相反的),然后,第二個(gè)參數(shù)是取得當(dāng)前等待得到的信號(hào)(這一點(diǎn),sigsuspend是做不到的)。
? ? sigwait的機(jī)制是:sigwait調(diào)用會(huì)自動(dòng)取消傳入?yún)?shù)信號(hào)集的阻塞狀態(tài),直到有新的信號(hào)被遞送,而在sigwait返回之前,它會(huì)把該等待到的信號(hào)從未決的信號(hào)集中去除,并恢復(fù)線程的信號(hào)屏蔽字。(APUE中文版關(guān)于這部份的翻譯是錯(cuò)的,請(qǐng)看英文版相關(guān)的描述。)。
? ? 如果信號(hào)被捕獲,而線而又正在用sigwait來(lái)等待該信號(hào)呢?那么這時(shí)就將由操作系統(tǒng)實(shí)現(xiàn)來(lái)決定以何種方式來(lái)遞關(guān)信號(hào)了,要么就遞送給sigwait,要么就遞送給信號(hào)處理程序,但僅只能選擇其中一種方式(在開發(fā)時(shí),最后還是僅選擇一種方式)。而sigsuspend則必須等待信號(hào)處理程序返回。
? ? sigwait常用的用法就是,使用一個(gè)專門的線程來(lái)處理信號(hào),而不像進(jìn)程那樣使用signal調(diào)用來(lái)設(shè)置handler。這是相當(dāng)有用的用法,進(jìn)程在一開始就屏蔽所有信號(hào),然后建立一個(gè)線程sigwait信號(hào),然后就是while true 和switch了。
下面有一個(gè)例子:
void *signal_handler(void *args) {sigset_t mask;int signo;// wait all signalssigfillset(&mask);while(1) {sigwait(&mask, &signo);switch (signo) {case SIGUSR1:// SIGUSR1 handlerbreak;case SIGINT:// SIGINT handlerbreak;.....default:fprintf(stderr, "unexpected signal %d\n", signo);break;}}return (void *) 0; }int main(int argc, char *argv[]) {pthread_t tid;sigset_t mask;// mask all signalssigfillset(&mask);pthread_sigmask(SIG_BLOCK, &mask, NULL);pthread_create(&tid, NULL, signal_handler, NULL);while (1) {printf("main thread: I am working......\n");sleep(1);}return 0; }5、那么線程的同步呢?哦,不應(yīng)該叫同步,而應(yīng)該叫通信。其實(shí)有另外的幾種辦法,一個(gè)是pthread_cond_broadcast,條件廣播,另一種就是利用線程sigwait,向指定線程發(fā)送信號(hào)pthread_kill。(本文未完,還欠代碼未寫,-_-||趕著洗碗去了)
轉(zhuǎn)載于:https://my.oschina.net/kut/blog/30120
總結(jié)
以上是生活随笔為你收集整理的Unix信号处理一些笔记的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Linux守护进程简介
- 下一篇: HDU_1075 What Are Yo