linux 信号_Linux中的信号处理机制 [四]
信號(hào)與線程
Unix的信號(hào)機(jī)制在誕生之初,生活在只有進(jìn)程(process)的相對(duì)單純的環(huán)境中。自從Unix世界有了線程(thread)的概念,信號(hào)就被賦予了發(fā)往進(jìn)程中某個(gè)特定線程的能力,當(dāng)然,這也增加了整個(gè)信號(hào)機(jī)制實(shí)現(xiàn)的復(fù)雜度。本系列的前面三篇文章都是基于進(jìn)程進(jìn)行的信號(hào)實(shí)現(xiàn)機(jī)制的討論,本文將著重介紹Linux中信號(hào)和線程之間的交互。
發(fā)送信號(hào)給線程無(wú)論是kill()還是sigqueue(),都只能向進(jìn)程發(fā)送信號(hào),在Linux中,要向進(jìn)程內(nèi)的線程發(fā)送信號(hào),需要使用tkill()或者tgkill():
int兩個(gè)函數(shù)中,"tid"都是代表目標(biāo)線程的PID,但tgkill()比tkill()多了一個(gè)"tgid"的參數(shù)。"tgid"是目標(biāo)線程所在進(jìn)程的PID,它可以用來(lái)防止向錯(cuò)誤的線程發(fā)送信號(hào)。
發(fā)送方給目標(biāo)線程發(fā)送信號(hào)時(shí),可能目標(biāo)線程已經(jīng)因?yàn)槟撤N原因退出了,按照Linux中PID的分配規(guī)則,退出線程/進(jìn)程的PID可被分配給其他的線程/進(jìn)程使用。這種情況下,如果使用tkill(),就可能出現(xiàn)將信號(hào)發(fā)送到不相干的線程上。引入"tgid"可以幫助進(jìn)行目標(biāo)線程所在進(jìn)程的校驗(yàn),這樣出現(xiàn)錯(cuò)發(fā)的可能性就被大大地降低了。
線程對(duì)信號(hào)的接收根據(jù)POSIX標(biāo)準(zhǔn)的定義,進(jìn)程內(nèi)的所有線程共享進(jìn)程的信號(hào)處理函數(shù),當(dāng)進(jìn)程內(nèi)的一個(gè)線程為某個(gè)信號(hào)注冊(cè)了處理函數(shù),另一個(gè)線程可以更改這個(gè)處理函數(shù)。在Linux的實(shí)現(xiàn)中,線程作為獨(dú)立的調(diào)度實(shí)體也有自己的task_struct,同一進(jìn)程的不同線程的task_struct的"sighand"將指向同一個(gè)包含信號(hào)處理函數(shù)列表的sighand_struct。
但是,每個(gè)線程可以有單獨(dú)的pending位圖/隊(duì)列和block位圖。如果一個(gè)信號(hào)是發(fā)送給線程的,那么內(nèi)核在遞送該信號(hào)時(shí),會(huì)將它放入線程私有的pending位圖/隊(duì)列中,之后根據(jù)目標(biāo)線程的block位圖的設(shè)置,直接由目標(biāo)線程處理就可以了。
如果信號(hào)是發(fā)送給一個(gè)進(jìn)程的,那么該信號(hào)在遞送時(shí)將被內(nèi)核放入進(jìn)程的pending位圖/隊(duì)列中,由進(jìn)程內(nèi)的所有線程共享。接下來(lái),內(nèi)核會(huì)從進(jìn)程的各個(gè)線程中,挑選一個(gè)block位圖中沒(méi)有屏蔽該信號(hào)的線程,來(lái)執(zhí)行對(duì)應(yīng)的信號(hào)處理函數(shù),其中,進(jìn)程的主線程將被內(nèi)核優(yōu)先選擇。
但是有一些信號(hào)是需要進(jìn)程內(nèi)的全體線程都做出響應(yīng)的,比如前面提到的令進(jìn)程聞風(fēng)喪膽的SIGKILL,它一旦到來(lái),就不會(huì)留下一個(gè)活口。
當(dāng)一個(gè)線程即將被內(nèi)核調(diào)度執(zhí)行,而該線程私有的penging位圖/隊(duì)列和所在進(jìn)程共享的penging位圖/隊(duì)列上都有待處理的信號(hào)時(shí),內(nèi)核將優(yōu)先向線程遞送私有的penging位圖/隊(duì)列上的信號(hào):
int作為Unix時(shí)代的產(chǎn)物,前面講到的sigprocmask()函數(shù)最初是用來(lái)設(shè)置進(jìn)程的block位圖的,但是同pending位圖/隊(duì)列不同的是,并沒(méi)有一個(gè)所謂的線程共享的block位圖的概念,所以在多線程環(huán)境下,sigprocmask()的語(yǔ)義也就變成了設(shè)置線程的block位圖。當(dāng)然,為了語(yǔ)義更加明顯,你可以使用POSIX線程庫(kù)提供的pthread_procmask()函數(shù),兩者的參數(shù)和行為都是一樣的。
參考:
- 《Linux環(huán)境編程:從應(yīng)用到內(nèi)核》第6章
- Understanding the Linux Kernel 第3版第11章
- UNIX Internals: The New Frontiers 第4章
- http://kernel.meizu.com/linux-signal.html
- https://www.ibm.com/developerworks/cn/linux/l-ipc/part2/index1.html?ca=drs-
原創(chuàng)文章,轉(zhuǎn)載請(qǐng)注明出處。
總結(jié)
以上是生活随笔為你收集整理的linux 信号_Linux中的信号处理机制 [四]的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 我国住房公积金制度到了该废除的时候了?
- 下一篇: 我国粮食总库存又多少,14亿人够吃多久?