• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            S.l.e!ep.¢%

            像打了激速一樣,以四倍的速度運(yùn)轉(zhuǎn),開(kāi)心的工作
            簡(jiǎn)單、開(kāi)放、平等的公司文化;尊重個(gè)性、自由與個(gè)人價(jià)值;
            posts - 1098, comments - 335, trackbacks - 0, articles - 1
              C++博客 :: 首頁(yè) :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理
            linux信號(hào)Linux下Signal信號(hào)太詳細(xì)了,終于找到了
            信號(hào)是Linux編程中非常重要的部分,本文將詳細(xì)介紹信號(hào)機(jī)制的基本概念、Linux對(duì)信號(hào)機(jī)制的大致實(shí)現(xiàn)方法、如何使用信號(hào),以及有關(guān)信號(hào)的幾個(gè)系統(tǒng)調(diào)用。

            信號(hào)機(jī)制是進(jìn)程之間相互傳遞消息的一種方法,信號(hào)全稱(chēng)為軟中斷信號(hào),也有人稱(chēng)作軟中斷。從它的命名可以看出,它的實(shí)質(zhì)和使用很象中斷。所以,信號(hào)可以說(shuō)是進(jìn)程控制的一部分。

            一、信號(hào)的基本概念

            本節(jié)先介紹信號(hào)的一些基本概念,然后給出一些基本的信號(hào)類(lèi)型和信號(hào)對(duì)應(yīng)的事件?;靖拍顚?duì)于理解和使用信號(hào),對(duì)于理解信號(hào)機(jī)制都特別重要。下面就來(lái)看看什么是信號(hào)。

            1、基本概念

            軟中斷信號(hào)(signal,又簡(jiǎn)稱(chēng)為信號(hào))用來(lái)通知進(jìn)程發(fā)生了異步事件。進(jìn)程之間可以互相通過(guò)系統(tǒng)調(diào)用kill發(fā)送軟中斷信號(hào)。內(nèi)核也可以因?yàn)閮?nèi)部事件而給進(jìn)程發(fā)送信號(hào),通知進(jìn)程發(fā)生了某個(gè)事件。注意,信號(hào)只是用來(lái)通知某進(jìn)程發(fā)生了什么事件,并不給該進(jìn)程傳遞任何數(shù)據(jù)。

            收 到信號(hào)的進(jìn)程對(duì)各種信號(hào)有不同的處理方法。處理方法可以分為三類(lèi):第一種是類(lèi)似中斷的處理程序,對(duì)于需要處理的信號(hào),進(jìn)程可以指定處理函數(shù),由該函數(shù)來(lái)處 理。第二種方法是,忽略某個(gè)信號(hào),對(duì)該信號(hào)不做任何處理,就象未發(fā)生過(guò)一樣。第三種方法是,對(duì)該信號(hào)的處理保留系統(tǒng)的默認(rèn)值,這種缺省操作,對(duì)大部分的信 號(hào)的缺省操作是使得進(jìn)程終止。進(jìn)程通過(guò)系統(tǒng)調(diào)用signal來(lái)指定進(jìn)程對(duì)某個(gè)信號(hào)的處理行為。

            在進(jìn)程表的表項(xiàng)中有一個(gè)軟中斷信號(hào)域,該域中每一位對(duì)應(yīng)一個(gè)信號(hào),當(dāng)有信號(hào)發(fā)送給進(jìn)程時(shí),對(duì)應(yīng)位置位。由此可以看出,進(jìn)程對(duì)不同的信號(hào)可以同時(shí)保留,但對(duì)于同一個(gè)信號(hào),進(jìn)程并不知道在處理之前來(lái)過(guò)多少個(gè)。

            2、信號(hào)的類(lèi)型

            發(fā)出信號(hào)的原因很多,這里按發(fā)出信號(hào)的原因簡(jiǎn)單分類(lèi),以了解各種信號(hào):

            (1) 與進(jìn)程終止相關(guān)的信號(hào)。當(dāng)進(jìn)程退出,或者子進(jìn)程終止時(shí),發(fā)出這類(lèi)信號(hào)。
            (2) 與進(jìn)程例外事件相關(guān)的信號(hào)。如進(jìn)程越界,或企圖寫(xiě)一個(gè)只讀的內(nèi)存區(qū)域(如程序正文區(qū)),或執(zhí)行一個(gè)特權(quán)指令及其他各種硬件錯(cuò)誤。
            (3) 與在系統(tǒng)調(diào)用期間遇到不可恢復(fù)條件相關(guān)的信號(hào)。如執(zhí)行系統(tǒng)調(diào)用exec時(shí),原有資源已經(jīng)釋放,而目前系統(tǒng)資源又已經(jīng)耗盡。
            (4) 與執(zhí)行系統(tǒng)調(diào)用時(shí)遇到非預(yù)測(cè)錯(cuò)誤條件相關(guān)的信號(hào)。如執(zhí)行一個(gè)并不存在的系統(tǒng)調(diào)用。
            (5) 在用戶(hù)態(tài)下的進(jìn)程發(fā)出的信號(hào)。如進(jìn)程調(diào)用系統(tǒng)調(diào)用kill向其他進(jìn)程發(fā)送信號(hào)。
            (6) 與終端交互相關(guān)的信號(hào)。如用戶(hù)關(guān)閉一個(gè)終端,或按下break鍵等情況。
            (7) 跟蹤進(jìn)程執(zhí)行的信號(hào)。

            Linux支持的信號(hào)列表如下。很多信號(hào)是與機(jī)器的體系結(jié)構(gòu)相關(guān)的,首先列出的是POSIX.1中列出的信號(hào):

            信號(hào) 值 處理動(dòng)作 發(fā)出信號(hào)的原因
            ----------------------------------------------------------------------
            SIGHUP 1 A 終端掛起或者控制進(jìn)程終止
            SIGINT 2 A 鍵盤(pán)中斷(如break鍵被按下)
            SIGQUIT 3 C 鍵盤(pán)的退出鍵被按下
            SIGILL 4 C 非法指令
            SIGABRT 6 C 由abort(3)發(fā)出的退出指令
            SIGFPE 8 C 浮點(diǎn)異常
            SIGKILL 9 AEF Kill信號(hào)
            SIGSEGV 11 C 無(wú)效的內(nèi)存引用
            SIGPIPE 13 A 管道破裂: 寫(xiě)一個(gè)沒(méi)有讀端口的管道
            SIGALRM 14 A 由alarm(2)發(fā)出的信號(hào)
            SIGTERM 15 A 終止信號(hào)
            SIGUSR1 30,10,16 A 用戶(hù)自定義信號(hào)1
            SIGUSR2 31,12,17 A 用戶(hù)自定義信號(hào)2
            SIGCHLD 20,17,18 B 子進(jìn)程結(jié)束信號(hào)
            SIGCONT 19,18,25 進(jìn)程繼續(xù)(曾被停止的進(jìn)程)
            SIGSTOP 17,19,23 DEF 終止進(jìn)程
            SIGTSTP 18,20,24 D 控制終端(tty)上按下停止鍵
            SIGTTIN 21,21,26 D 后臺(tái)進(jìn)程企圖從控制終端讀
            SIGTTOU 22,22,27 D 后臺(tái)進(jìn)程企圖從控制終端寫(xiě)

            下面的信號(hào)沒(méi)在POSIX.1中列出,而在SUSv2列出

            信號(hào) 值 處理動(dòng)作 發(fā)出信號(hào)的原因
            --------------------------------------------------------------------
            SIGBUS 10,7,10 C 總線(xiàn)錯(cuò)誤(錯(cuò)誤的內(nèi)存訪(fǎng)問(wèn))
            SIGPOLL A Sys V定義的Pollable事件,與SIGIO同義
            SIGPROF 27,27,29 A Profiling定時(shí)器到
            SIGSYS 12,-,12 C 無(wú)效的系統(tǒng)調(diào)用 (SVID)
            SIGTRAP 5 C 跟蹤/斷點(diǎn)捕獲
            SIGURG 16,23,21 B Socket出現(xiàn)緊急條件(4.2 BSD)
            SIGVTALRM 26,26,28 A 實(shí)際時(shí)間報(bào)警時(shí)鐘信號(hào)(4.2 BSD)
            SIGXCPU 24,24,30 C 超出設(shè)定的CPU時(shí)間限制(4.2 BSD)
            SIGXFSZ 25,25,31 C 超出設(shè)定的文件大小限制(4.2 BSD)

            (對(duì)于SIGSYS,SIGXCPU,SIGXFSZ,以及某些機(jī)器體系結(jié)構(gòu)下的SIGBUS,Linux缺省的動(dòng)作是A (terminate),SUSv2 是C (terminate and dump core))。

            下面是其它的一些信號(hào)

            信號(hào) 值 處理動(dòng)作 發(fā)出信號(hào)的原因
            ----------------------------------------------------------------------
            SIGIOT 6 C IO捕獲指令,與SIGABRT同義
            SIGEMT 7,-,7
            SIGSTKFLT -,16,- A 協(xié)處理器堆棧錯(cuò)誤
            SIGIO 23,29,22 A 某I/O操作現(xiàn)在可以進(jìn)行了(4.2 BSD)
            SIGCLD -,-,18 A 與SIGCHLD同義
            SIGPWR 29,30,19 A 電源故障(System V)
            SIGINFO 29,-,- A 與SIGPWR同義
            SIGLOST -,-,- A 文件鎖丟失
            SIGWINCH 28,28,20 B 窗口大小改變(4.3 BSD, Sun)
            SIGUNUSED -,31,- A 未使用的信號(hào)(will be SIGSYS)

            (在這里,- 表示信號(hào)沒(méi)有實(shí)現(xiàn);有三個(gè)值給出的含義為,第一個(gè)值通常在Alpha和Sparc上有效,中間的值對(duì)應(yīng)i386和ppc以及sh,最后一個(gè)值對(duì)應(yīng)mips。信號(hào)29在Alpha上為SIGINFO / SIGPWR ,在Sparc上為SIGLOST。)

            處理動(dòng)作一項(xiàng)中的字母含義如下
            A 缺省的動(dòng)作是終止進(jìn)程
            B 缺省的動(dòng)作是忽略此信號(hào)
            C 缺省的動(dòng)作是終止進(jìn)程并進(jìn)行內(nèi)核映像轉(zhuǎn)儲(chǔ)(dump core)
            D 缺省的動(dòng)作是停止進(jìn)程
            E 信號(hào)不能被捕獲
            F 信號(hào)不能被忽略

            上 面介紹的信號(hào)是常見(jiàn)系統(tǒng)所支持的。以表格的形式介紹了各種信號(hào)的名稱(chēng)、作用及其在默認(rèn)情況下的處理動(dòng)作。各種默認(rèn)處理動(dòng)作的含義是:終止程序是指進(jìn)程退 出;忽略該信號(hào)是將該信號(hào)丟棄,不做處理;停止程序是指程序掛起,進(jìn)入停止?fàn)顩r以后還能重新進(jìn)行下去,一般是在調(diào)試的過(guò)程中(例如ptrace系統(tǒng)調(diào) 用);內(nèi)核映像轉(zhuǎn)儲(chǔ)是指將進(jìn)程數(shù)據(jù)在內(nèi)存的映像和進(jìn)程在內(nèi)核結(jié)構(gòu)中存儲(chǔ)的部分內(nèi)容以一定格式轉(zhuǎn)儲(chǔ)到文件系統(tǒng),并且進(jìn)程退出執(zhí)行,這樣做的好處是為程序員提 供了方便,使得他們可以得到進(jìn)程當(dāng)時(shí)執(zhí)行時(shí)的數(shù)據(jù)值,允許他們確定轉(zhuǎn)儲(chǔ)的原因,并且可以調(diào)試他們的程序。

            注意 信號(hào)SIGKILL和SIGSTOP既不能被捕捉,也不能被忽略。信號(hào)SIGIOT與SIGABRT是一個(gè)信號(hào)??梢钥闯?,同一個(gè)信號(hào)在不同的系統(tǒng)中值可能不一樣,所以建議最好使用為信號(hào)定義的名字,而不要直接使用信號(hào)的值。

            二、信 號(hào) 機(jī) 制

            上 一節(jié)中介紹了信號(hào)的基本概念,在這一節(jié)中,我們將介紹內(nèi)核如何實(shí)現(xiàn)信號(hào)機(jī)制。即內(nèi)核如何向一個(gè)進(jìn)程發(fā)送信號(hào)、進(jìn)程如何接收一個(gè)信號(hào)、進(jìn)程怎樣控制自己對(duì)信 號(hào)的反應(yīng)、內(nèi)核在什么時(shí)機(jī)處理和怎樣處理進(jìn)程收到的信號(hào)。還要介紹一下setjmp和longjmp在信號(hào)中起到的作用。

            1、內(nèi)核對(duì)信號(hào)的基本處理方法

            內(nèi) 核給一個(gè)進(jìn)程發(fā)送軟中斷信號(hào)的方法,是在進(jìn)程所在的進(jìn)程表項(xiàng)的信號(hào)域設(shè)置對(duì)應(yīng)于該信號(hào)的位。這里要補(bǔ)充的是,如果信號(hào)發(fā)送給一個(gè)正在睡眠的進(jìn)程,那么要看 該進(jìn)程進(jìn)入睡眠的優(yōu)先級(jí),如果進(jìn)程睡眠在可被中斷的優(yōu)先級(jí)上,則喚醒進(jìn)程;否則僅設(shè)置進(jìn)程表中信號(hào)域相應(yīng)的位,而不喚醒進(jìn)程。這一點(diǎn)比較重要,因?yàn)檫M(jìn)程檢 查是否收到信號(hào)的時(shí)機(jī)是:一個(gè)進(jìn)程在即將從內(nèi)核態(tài)返回到用戶(hù)態(tài)時(shí);或者,在一個(gè)進(jìn)程要進(jìn)入或離開(kāi)一個(gè)適當(dāng)?shù)牡驼{(diào)度優(yōu)先級(jí)睡眠狀態(tài)時(shí)。

            內(nèi)核處理一個(gè)進(jìn)程收到的信號(hào)的時(shí)機(jī)是在一個(gè)進(jìn)程從內(nèi)核態(tài)返回用戶(hù)態(tài)時(shí)。所以,當(dāng)一個(gè)進(jìn)程在內(nèi)核態(tài)下運(yùn)行時(shí),軟中斷信號(hào)并不立即起作用,要等到將返回用戶(hù)態(tài)時(shí)才處理。進(jìn)程只有處理完信號(hào)才會(huì)返回用戶(hù)態(tài),進(jìn)程在用戶(hù)態(tài)下不會(huì)有未處理完的信號(hào)。

            內(nèi) 核處理一個(gè)進(jìn)程收到的軟中斷信號(hào)是在該進(jìn)程的上下文中,因此,進(jìn)程必須處于運(yùn)行狀態(tài)。前面介紹概念的時(shí)候講過(guò),處理信號(hào)有三種類(lèi)型:進(jìn)程接收到信號(hào)后退 出;進(jìn)程忽略該信號(hào);進(jìn)程收到信號(hào)后執(zhí)行用戶(hù)設(shè)定用系統(tǒng)調(diào)用signal的函數(shù)。當(dāng)進(jìn)程接收到一個(gè)它忽略的信號(hào)時(shí),進(jìn)程丟棄該信號(hào),就象沒(méi)有收到該信號(hào)似 的繼續(xù)運(yùn)行。如果進(jìn)程收到一個(gè)要捕捉的信號(hào),那么進(jìn)程從內(nèi)核態(tài)返回用戶(hù)態(tài)時(shí)執(zhí)行用戶(hù)定義的函數(shù)。而且執(zhí)行用戶(hù)定義的函數(shù)的方法很巧妙,內(nèi)核是在用戶(hù)棧上創(chuàng) 建一個(gè)新的層,該層中將返回地址的值設(shè)置成用戶(hù)定義的處理函數(shù)的地址,這樣進(jìn)程從內(nèi)核返回彈出棧頂時(shí)就返回到用戶(hù)定義的函數(shù)處,從函數(shù)返回再?gòu)棾鰲m敃r(shí), 才返回原先進(jìn)入內(nèi)核的地方。這樣做的原因是用戶(hù)定義的處理函數(shù)不能且不允許在內(nèi)核態(tài)下執(zhí)行(如果用戶(hù)定義的函數(shù)在內(nèi)核態(tài)下運(yùn)行的話(huà),用戶(hù)就可以獲得任何權(quán) 限)。

            在信號(hào)的處理方法中有幾點(diǎn)特別要引起注意。第一,在一些系統(tǒng)中,當(dāng)一個(gè)進(jìn)程處理完中斷信號(hào)返回用戶(hù)態(tài)之前,內(nèi)核清除用戶(hù)區(qū)中設(shè) 定的對(duì)該信號(hào)的處理例程的地址,即下一次進(jìn)程對(duì)該信號(hào)的處理方法又改為默認(rèn)值,除非在下一次信號(hào)到來(lái)之前再次使用signal系統(tǒng)調(diào)用。這可能會(huì)使得進(jìn)程 在調(diào)用signal之前又得到該信號(hào)而導(dǎo)致退出。在BSD中,內(nèi)核不再清除該地址。但不清除該地址可能使得進(jìn)程因?yàn)檫^(guò)多過(guò)快的得到某個(gè)信號(hào)而導(dǎo)致堆棧溢 出。為了避免出現(xiàn)上述情況。在BSD系統(tǒng)中,內(nèi)核模擬了對(duì)硬件中斷的處理方法,即在處理某個(gè)中斷時(shí),阻止接收新的該類(lèi)中斷。

            第二個(gè)要 引起注意的是,如果要捕捉的信號(hào)發(fā)生于進(jìn)程正在一個(gè)系統(tǒng)調(diào)用中時(shí),并且該進(jìn)程睡眠在可中斷的優(yōu)先級(jí)上,這時(shí)該信號(hào)引起進(jìn)程作一次longjmp,跳出睡眠 狀態(tài),返回用戶(hù)態(tài)并執(zhí)行信號(hào)處理例程。當(dāng)從信號(hào)處理例程返回時(shí),進(jìn)程就象從系統(tǒng)調(diào)用返回一樣,但返回了一個(gè)錯(cuò)誤代碼,指出該次系統(tǒng)調(diào)用曾經(jīng)被中斷。這要注 意的是,BSD系統(tǒng)中內(nèi)核可以自動(dòng)地重新開(kāi)始系統(tǒng)調(diào)用。

            第三個(gè)要注意的地方:若進(jìn)程睡眠在可中斷的優(yōu)先級(jí)上,則當(dāng)它收到一個(gè)要忽略的信號(hào)時(shí),該進(jìn)程被喚醒,但不做longjmp,一般是繼續(xù)睡眠。但用戶(hù)感覺(jué)不到進(jìn)程曾經(jīng)被喚醒,而是象沒(méi)有發(fā)生過(guò)該信號(hào)一樣。

            第 四個(gè)要注意的地方:內(nèi)核對(duì)子進(jìn)程終止(SIGCLD)信號(hào)的處理方法與其他信號(hào)有所區(qū)別。當(dāng)進(jìn)程檢查出收到了一個(gè)子進(jìn)程終止的信號(hào)時(shí),缺省情況下,該進(jìn)程 就象沒(méi)有收到該信號(hào)似的,如果父進(jìn)程執(zhí)行了系統(tǒng)調(diào)用wait,進(jìn)程將從系統(tǒng)調(diào)用wait中醒來(lái)并返回wait調(diào)用,執(zhí)行一系列wait調(diào)用的后續(xù)操作(找 出僵死的子進(jìn)程,釋放子進(jìn)程的進(jìn)程表項(xiàng)),然后從wait中返回。SIGCLD信號(hào)的作用是喚醒一個(gè)睡眠在可被中斷優(yōu)先級(jí)上的進(jìn)程。如果該進(jìn)程捕捉了這個(gè) 信號(hào),就象普通信號(hào)處理一樣轉(zhuǎn)到處理例程。如果進(jìn)程忽略該信號(hào),那么系統(tǒng)調(diào)用wait的動(dòng)作就有所不同,因?yàn)镾IGCLD的作用僅僅是喚醒一個(gè)睡眠在可被 中斷優(yōu)先級(jí)上的進(jìn)程,那么執(zhí)行wait調(diào)用的父進(jìn)程被喚醒繼續(xù)執(zhí)行wait調(diào)用的后續(xù)操作,然后等待其他的子進(jìn)程。

            如果一個(gè)進(jìn)程調(diào)用signal系統(tǒng)調(diào)用,并設(shè)置了SIGCLD的處理方法,并且該進(jìn)程有子進(jìn)程處于僵死狀態(tài),則內(nèi)核將向該進(jìn)程發(fā)一個(gè)SIGCLD信號(hào)。

            2、setjmp和longjmp的作用

            前面在介紹信號(hào)處理機(jī)制時(shí),多次提到了setjmp和longjmp,但沒(méi)有仔細(xì)說(shuō)明它們的作用和實(shí)現(xiàn)方法。這里就此作一個(gè)簡(jiǎn)單的介紹。

            在 介紹信號(hào)的時(shí)候,我們看到多個(gè)地方要求進(jìn)程在檢查收到信號(hào)后,從原來(lái)的系統(tǒng)調(diào)用中直接返回,而不是等到該調(diào)用完成。這種進(jìn)程突然改變其上下文的情況,就是 使用setjmp和longjmp的結(jié)果。setjmp將保存的上下文存入用戶(hù)區(qū),并繼續(xù)在舊的上下文中執(zhí)行。這就是說(shuō),進(jìn)程執(zhí)行一個(gè)系統(tǒng)調(diào)用,當(dāng)因?yàn)橘Y 源或其他原因要去睡眠時(shí),內(nèi)核為進(jìn)程作了一次setjmp,如果在睡眠中被信號(hào)喚醒,進(jìn)程不能再進(jìn)入睡眠時(shí),內(nèi)核為進(jìn)程調(diào)用longjmp,該操作是內(nèi)核 為進(jìn)程將原先setjmp調(diào)用保存在進(jìn)程用戶(hù)區(qū)的上下文恢復(fù)成現(xiàn)在的上下文,這樣就使得進(jìn)程可以恢復(fù)等待資源前的狀態(tài),而且內(nèi)核為setjmp返回1,使 得進(jìn)程知道該次系統(tǒng)調(diào)用失敗。這就是它們的作用。

            三、有關(guān)信號(hào)的系統(tǒng)調(diào)用

            前面兩節(jié)已經(jīng)介紹了有關(guān)信號(hào)的大部分知 識(shí)。這一節(jié)我們來(lái)了解一下這些系統(tǒng)調(diào)用。其中,系統(tǒng)調(diào)用signal是進(jìn)程用來(lái)設(shè)定某個(gè)信號(hào)的處理方法,系統(tǒng)調(diào)用kill是用來(lái)發(fā)送信號(hào)給指定進(jìn)程的。這 兩個(gè)調(diào)用可以形成信號(hào)的基本操作。后兩個(gè)調(diào)用pause和alarm是通過(guò)信號(hào)實(shí)現(xiàn)的進(jìn)程暫停和定時(shí)器,調(diào)用alarm是通過(guò)信號(hào)通知進(jìn)程定時(shí)器到時(shí)。所 以在這里,我們還要介紹這兩個(gè)調(diào)用。

            1、signal 系統(tǒng)調(diào)用

            系統(tǒng)調(diào)用signal用來(lái)設(shè)定某個(gè)信號(hào)的處理方法。該調(diào)用聲明的格式如下:
            void (*signal(int signum, void (*handler)(int)))(int);
            在使用該調(diào)用的進(jìn)程中加入以下頭文件:
            #include

            上述聲明格式比較復(fù)雜,如果不清楚如何使用,也可以通過(guò)下面這種類(lèi)型定義的格式來(lái)使用(POSIX的定義):
            typedef void (*sighandler_t)(int);
            sighandler_t signal(int signum, sighandler_t handler);
            但這種格式在不同的系統(tǒng)中有不同的類(lèi)型定義,所以要使用這種格式,最好還是參考一下聯(lián)機(jī)手冊(cè)。

            在調(diào)用中,參數(shù)signum指出要設(shè)置處理方法的信號(hào)。第二個(gè)參數(shù)handler是一個(gè)處理函數(shù),或者是
            SIG_IGN:忽略參數(shù)signum所指的信號(hào)。
            SIG_DFL:恢復(fù)參數(shù)signum所指信號(hào)的處理方法為默認(rèn)值。

            傳遞給信號(hào)處理例程的整數(shù)參數(shù)是信號(hào)值,這樣可以使得一個(gè)信號(hào)處理例程處理多個(gè)信號(hào)。系統(tǒng)調(diào)用signal返回值是指定信號(hào)signum前一次的處理例程或者錯(cuò)誤時(shí)返回錯(cuò)誤代碼SIG_ERR。下面來(lái)看一個(gè)簡(jiǎn)單的例子:

            #include
            #include
            #include
            void sigroutine(int dunno) { /* 信號(hào)處理例程,其中dunno將會(huì)得到信號(hào)的值 */
            switch (dunno) {
            case 1:
            printf("Get a signal -- SIGHUP ");
            break;
            case 2:
            printf("Get a signal -- SIGINT ");
            break;
            case 3:
            printf("Get a signal -- SIGQUIT ");
            break;
            }
            return;
            }

            int main() {
            printf("process id is %d ",getpid());
            signal(SIGHUP, sigroutine); //* 下面設(shè)置三個(gè)信號(hào)的處理方法
            signal(SIGINT, sigroutine);
            signal(SIGQUIT, sigroutine);
            for (;;) ;
            }

            其中信號(hào)SIGINT由按下Ctrl-C發(fā)出,信號(hào)SIGQUIT由按下Ctrl-發(fā)出。該程序執(zhí)行的結(jié)果如下:

            localhost:~$ ./sig_test
            process id is 463
            Get a signal -SIGINT //按下Ctrl-C得到的結(jié)果
            Get a signal -SIGQUIT //按下Ctrl-得到的結(jié)果
            //按下Ctrl-z將進(jìn)程置于后臺(tái)
            [1]+ Stopped ./sig_test
            localhost:~$ bg
            [1]+ ./sig_test &
            localhost:~$ kill -HUP 463 //向進(jìn)程發(fā)送SIGHUP信號(hào)
            localhost:~$ Get a signal – SIGHUP
            kill -9 463 //向進(jìn)程發(fā)送SIGKILL信號(hào),終止進(jìn)程
            localhost:~$

            2、kill 系統(tǒng)調(diào)用

            系統(tǒng)調(diào)用kill用來(lái)向進(jìn)程發(fā)送一個(gè)信號(hào)。該調(diào)用聲明的格式如下:
            int kill(pid_t pid, int sig);
            在使用該調(diào)用的進(jìn)程中加入以下頭文件:
            #include
            #include

            該 系統(tǒng)調(diào)用可以用來(lái)向任何進(jìn)程或進(jìn)程組發(fā)送任何信號(hào)。如果參數(shù)pid是正數(shù),那么該調(diào)用將信號(hào)sig發(fā)送到進(jìn)程號(hào)為pid的進(jìn)程。如果pid等于0,那么信 號(hào)sig將發(fā)送給當(dāng)前進(jìn)程所屬進(jìn)程組里的所有進(jìn)程。如果參數(shù)pid等于-1,信號(hào)sig將發(fā)送給除了進(jìn)程1和自身以外的所有進(jìn)程。如果參數(shù)pid小于- 1,信號(hào)sig將發(fā)送給屬于進(jìn)程組-pid的所有進(jìn)程。如果參數(shù)sig為0,將不發(fā)送信號(hào)。該調(diào)用執(zhí)行成功時(shí),返回值為0;錯(cuò)誤時(shí),返回-1,并設(shè)置相應(yīng) 的錯(cuò)誤代碼errno。下面是一些可能返回的錯(cuò)誤代碼:
            EINVAL:指定的信號(hào)sig無(wú)效。
            ESRCH:參數(shù)pid指定的進(jìn)程或進(jìn)程組不存在。注意,在進(jìn)程表項(xiàng)中存在的進(jìn)程,可能是一個(gè)還沒(méi)有被wait收回,但已經(jīng)終止執(zhí)行的僵死進(jìn)程。
            EPERM: 進(jìn)程沒(méi)有權(quán)力將這個(gè)信號(hào)發(fā)送到指定接收信號(hào)的進(jìn)程。因?yàn)?,一個(gè)進(jìn)程被允許將信號(hào)發(fā)送到進(jìn)程pid時(shí),必須擁有root權(quán)力,或者是發(fā)出調(diào)用的進(jìn)程的UID 或EUID與指定接收的進(jìn)程的UID或保存用戶(hù)ID(savedset-user-ID)相同。如果參數(shù)pid小于-1,即該信號(hào)發(fā)送給一個(gè)組,則該錯(cuò)誤 表示組中有成員進(jìn)程不能接收該信號(hào)。

            3、pause系統(tǒng)調(diào)用

            系統(tǒng)調(diào)用pause的作用是等待一個(gè)信號(hào)。該調(diào)用的聲明格式如下:
            int pause(void);
            在使用該調(diào)用的進(jìn)程中加入以下頭文件:
            #include

            該調(diào)用使得發(fā)出調(diào)用的進(jìn)程進(jìn)入睡眠,直到接收到一個(gè)信號(hào)為止。該調(diào)用總是返回-1,并設(shè)置錯(cuò)誤代碼為EINTR(接收到一個(gè)信號(hào))。下面是一個(gè)簡(jiǎn)單的范例:

            #include
            #include
            #include
            void sigroutine(int unused) {
            printf("Catch a signal SIGINT ");
            }

            int main() {
            signal(SIGINT, sigroutine);
            pause();
            printf("receive a signal ");
            }

            在這個(gè)例子中,程序開(kāi)始執(zhí)行,就象進(jìn)入了死循環(huán)一樣,這是因?yàn)檫M(jìn)程正在等待信號(hào),當(dāng)我們按下Ctrl-C時(shí),信號(hào)被捕捉,并且使得pause退出等待狀態(tài)。

            4、alarm和 setitimer系統(tǒng)調(diào)用

            系統(tǒng)調(diào)用alarm的功能是設(shè)置一個(gè)定時(shí)器,當(dāng)定時(shí)器計(jì)時(shí)到達(dá)時(shí),將發(fā)出一個(gè)信號(hào)給進(jìn)程。該調(diào)用的聲明格式如下:
            unsigned int alarm(unsigned int seconds);
            在使用該調(diào)用的進(jìn)程中加入以下頭文件:
            #include

            系 統(tǒng)調(diào)用alarm安排內(nèi)核為調(diào)用進(jìn)程在指定的seconds秒后發(fā)出一個(gè)SIGALRM的信號(hào)。如果指定的參數(shù)seconds為0,則不再發(fā)送 SIGALRM信號(hào)。后一次設(shè)定將取消前一次的設(shè)定。該調(diào)用返回值為上次定時(shí)調(diào)用到發(fā)送之間剩余的時(shí)間,或者因?yàn)闆](méi)有前一次定時(shí)調(diào)用而返回0。

            注意,在使用時(shí),alarm只設(shè)定為發(fā)送一次信號(hào),如果要多次發(fā)送,就要多次使用alarm調(diào)用。

            對(duì)于alarm,這里不再舉例。現(xiàn)在的系統(tǒng)中很多程序不再使用alarm調(diào)用,而是使用setitimer調(diào)用來(lái)設(shè)置定時(shí)器,用getitimer來(lái)得到定時(shí)器的狀態(tài),這兩個(gè)調(diào)用的聲明格式如下:
            int getitimer(int which, struct itimerval *value);
            int setitimer(int which, const struct itimerval *value, struct itimerval *ovalue);
            在使用這兩個(gè)調(diào)用的進(jìn)程中加入以下頭文件:
            #include

            該系統(tǒng)調(diào)用給進(jìn)程提供了三個(gè)定時(shí)器,它們各自有其獨(dú)有的計(jì)時(shí)域,當(dāng)其中任何一個(gè)到達(dá),就發(fā)送一個(gè)相應(yīng)的信號(hào)給進(jìn)程,并使得計(jì)時(shí)器重新開(kāi)始。三個(gè)計(jì)時(shí)器由參數(shù)which指定,如下所示:
            TIMER_REAL:按實(shí)際時(shí)間計(jì)時(shí),計(jì)時(shí)到達(dá)將給進(jìn)程發(fā)送SIGALRM信號(hào)。
            ITIMER_VIRTUAL:僅當(dāng)進(jìn)程執(zhí)行時(shí)才進(jìn)行計(jì)時(shí)。計(jì)時(shí)到達(dá)將發(fā)送SIGVTALRM信號(hào)給進(jìn)程。
            ITIMER_PROF:當(dāng)進(jìn)程執(zhí)行時(shí)和系統(tǒng)為該進(jìn)程執(zhí)行動(dòng)作時(shí)都計(jì)時(shí)。與ITIMER_VIR-TUAL是一對(duì),該定時(shí)器經(jīng)常用來(lái)統(tǒng)計(jì)進(jìn)程在用戶(hù)態(tài)和內(nèi)核態(tài)花費(fèi)的時(shí)間。計(jì)時(shí)到達(dá)將發(fā)送SIGPROF信號(hào)給進(jìn)程。

            定時(shí)器中的參數(shù)value用來(lái)指明定時(shí)器的時(shí)間,其結(jié)構(gòu)如下:
            struct itimerval {
            struct timeval it_interval; /* 下一次的取值 */
            struct timeval it_value; /* 本次的設(shè)定值 */
            };

            該結(jié)構(gòu)中timeval結(jié)構(gòu)定義如下:
            struct timeval {
            long tv_sec; /* 秒 */
            long tv_usec; /* 微秒,1秒 = 1000000 微秒*/
            };

            在setitimer 調(diào)用中,參數(shù)ovalue如果不為空,則其中保留的是上次調(diào)用設(shè)定的值。定時(shí)器將it_value遞減到0時(shí),產(chǎn)生一個(gè)信號(hào),并將it_value的值設(shè) 定為it_interval的值,然后重新開(kāi)始計(jì)時(shí),如此往復(fù)。當(dāng)it_value設(shè)定為0時(shí),計(jì)時(shí)器停止,或者當(dāng)它計(jì)時(shí)到期,而it_interval 為0時(shí)停止。調(diào)用成功時(shí),返回0;錯(cuò)誤時(shí),返回-1,并設(shè)置相應(yīng)的錯(cuò)誤代碼errno:
            EFAULT:參數(shù)value或ovalue是無(wú)效的指針。
            EINVAL:參數(shù)which不是ITIMER_REAL、ITIMER_VIRT或ITIMER_PROF中的一個(gè)。

            下面是關(guān)于setitimer調(diào)用的一個(gè)簡(jiǎn)單示范,在該例子中,每隔一秒發(fā)出一個(gè)SIGALRM,每隔0.5秒發(fā)出一個(gè)SIGVTALRM信號(hào):

            #include
            #include
            #include
            #include
            int sec;

            void sigroutine(int signo) {
            switch (signo) {
            case SIGALRM:
            printf("Catch a signal -- SIGALRM ");
            break;
            case SIGVTALRM:
            printf("Catch a signal -- SIGVTALRM ");
            break;
            }
            return;
            }

            int main() {
            struct itimerval value,ovalue,value2;
            sec = 5;

            printf("process id is %d ",getpid());
            signal(SIGALRM, sigroutine);
            signal(SIGVTALRM, sigroutine);

            value.it_value.tv_sec = 1;
            value.it_value.tv_usec = 0;
            value.it_interval.tv_sec = 1;
            value.it_interval.tv_usec = 0;
            setitimer(ITIMER_REAL, &value, &ovalue);

            value2.it_value.tv_sec = 0;
            value2.it_value.tv_usec = 500000;
            value2.it_interval.tv_sec = 0;
            value2.it_interval.tv_usec = 500000;
            setitimer(ITIMER_VIRTUAL, &value2, &ovalue);

            for (;;) ;
            }

            該例子的屏幕拷貝如下:

            localhost:~$ ./timer_test
            process id is 579
            Catch a signal – SIGVTALRM
            Catch a signal – SIGALRM
            Catch a signal – SIGVTALRM
            Catch a signal – SIGVTALRM
            Catch a signal – SIGALRM
            Catch a signal –GVTALRM

            Feedback

            # re: linux信號(hào)Linux下Signal信號(hào)太詳細(xì)了,終于找到了  回復(fù)  更多評(píng)論   

            2015-05-28 11:18 by 11
            這篇文章就是個(gè)垃圾

            # re: linux信號(hào)Linux下Signal信號(hào)太詳細(xì)了,終于找到了  回復(fù)  更多評(píng)論   

            2016-08-17 07:40 by zsx
            寫(xiě)的不錯(cuò)。
            色综合合久久天天综合绕视看| 乱亲女H秽乱长久久久| segui久久国产精品| 99久久精品国产高清一区二区 | 伊人久久综合成人网| 日韩影院久久| 久久精品国产欧美日韩99热| 亚洲精品无码久久久| 久久久久99这里有精品10 | 一本色道久久99一综合| 久久亚洲精品无码播放| 久久99精品久久久久久噜噜 | 狠狠色丁香久久婷婷综合_中| 少妇久久久久久被弄到高潮| 久久婷婷五月综合97色直播| 亚洲精品无码久久毛片| 国产偷久久久精品专区| 久久亚洲私人国产精品vA| 国内精品伊人久久久久AV影院| 国产精品久久久久久影院| 国产成人99久久亚洲综合精品| 国产农村妇女毛片精品久久| 国产午夜精品理论片久久| 欧美久久一级内射wwwwww.| 久久天天躁狠狠躁夜夜躁2014| 精品久久人人爽天天玩人人妻| 久久精品无码专区免费东京热| 久久99精品国产99久久| 久久久久久噜噜精品免费直播| 国产精品久久新婚兰兰| 久久精品国产亚洲AV高清热| 精品久久久久久国产牛牛app | 久久人人爽爽爽人久久久| 久久九九全国免费| 久久综合伊人77777| 久久综合国产乱子伦精品免费| 伊人久久大香线蕉精品| 久久毛片一区二区| 精品久久久久久无码中文字幕一区| 国产视频久久| 一本色道久久88—综合亚洲精品|