日本黄色一级经典视频|伊人久久精品视频|亚洲黄色色周成人视频九九九|av免费网址黄色小短片|黄色Av无码亚洲成年人|亚洲1区2区3区无码|真人黄片免费观看|无码一级小说欧美日免费三级|日韩中文字幕91在线看|精品久久久无码中文字幕边打电话

當(dāng)前位置:首頁(yè) > 嵌入式 > 嵌入式教程
[導(dǎo)讀]信號(hào)是UNIX中所使用的進(jìn)程通信的一種最古老的方法。它是在軟件層次上對(duì)中斷機(jī)制的一種模擬,是一種異步通信方式。信號(hào)可以直接進(jìn)行用戶空間進(jìn)程和內(nèi)核進(jìn)程之間的交互,內(nèi)核進(jìn)程也可以利用它來(lái)通知用戶空間進(jìn)程發(fā)生了哪些系統(tǒng)事件。它可以在任何時(shí)候發(fā)給某一進(jìn)程,而無(wú)需知道該進(jìn)程的狀態(tài)。

8.3信號(hào)8.3.1信號(hào)概述

信號(hào)是UNIX中所使用的進(jìn)程通信的一種最古老的方法。它是在軟件層次上對(duì)中斷機(jī)制的一種模擬,是一種異步通信方式。信號(hào)可以直接進(jìn)行用戶空間進(jìn)程和內(nèi)核進(jìn)程之間的交互,內(nèi)核進(jìn)程也可以利用它來(lái)通知用戶空間進(jìn)程發(fā)生了哪些系統(tǒng)事件。它可以在任何時(shí)候發(fā)給某一進(jìn)程,而無(wú)需知道該進(jìn)程的狀態(tài)。如果該進(jìn)程當(dāng)前并未處于執(zhí)行態(tài),則該信號(hào)就由內(nèi)核保存起來(lái),直到該進(jìn)程恢復(fù)執(zhí)行再傳遞給它為止;如果一個(gè)信號(hào)被進(jìn)程設(shè)置為阻塞,則該信號(hào)的傳遞被延遲,直到其阻塞被取消時(shí)才被傳遞給進(jìn)程。

在第2章kill命令中曾講解到“−l”選項(xiàng),這個(gè)選項(xiàng)可以列出該系統(tǒng)所支持的所有信號(hào)的列表。在筆者的系統(tǒng)中,信號(hào)值在32之前的則有不同的名稱,而信號(hào)值在32以后的都是用“SIGRTMIN”或“SIGRTMAX”開(kāi)頭的,這就是兩類典型的信號(hào)。前者是從UNIX系統(tǒng)中繼承下來(lái)的信號(hào),為不可靠信號(hào)(也稱為非實(shí)時(shí)信號(hào));后者是為了解決前面“不可靠信號(hào)”的問(wèn)題而進(jìn)行了更改和擴(kuò)充的信號(hào),稱為“可靠信號(hào)”(也稱為實(shí)時(shí)信號(hào))。那么為什么之前的信號(hào)不可靠呢?這里首先要介紹一下信號(hào)的生命周期。

一個(gè)完整的信號(hào)生命周期可以分為3個(gè)重要階段,這3個(gè)階段由4個(gè)重要事件來(lái)刻畫(huà)的:信號(hào)產(chǎn)生、信號(hào)在進(jìn)程中注冊(cè)、信號(hào)在進(jìn)程中注銷、執(zhí)行信號(hào)處理函數(shù),如圖8.6所示。相鄰兩個(gè)事件的時(shí)間間隔構(gòu)成信號(hào)生命周期的一個(gè)階段。要注意這里的信號(hào)處理有多種方式,一般是由內(nèi)核完成的,當(dāng)然也可以由用戶進(jìn)程來(lái)完成,故在此沒(méi)有明確畫(huà)出。

圖8.6信號(hào)生命周期

一個(gè)不可靠信號(hào)的處理過(guò)程是這樣的:如果發(fā)現(xiàn)該信號(hào)已經(jīng)在進(jìn)程中注冊(cè),那么就忽略該信號(hào)。因此,若前一個(gè)信號(hào)還未注銷又產(chǎn)生了相同的信號(hào)就會(huì)產(chǎn)生信號(hào)丟失。而當(dāng)可靠信號(hào)發(fā)送給一個(gè)進(jìn)程時(shí),不管該信號(hào)是否已經(jīng)在進(jìn)程中注冊(cè),都會(huì)被再注冊(cè)一次,因此信號(hào)就不會(huì)丟失。所有可靠信號(hào)都支持排隊(duì),而所有不可靠信號(hào)都不支持排隊(duì)。

注意

這里信號(hào)的產(chǎn)生、注冊(cè)和注銷等是指信號(hào)的內(nèi)部實(shí)現(xiàn)機(jī)制,而不是調(diào)用信號(hào)的函數(shù)實(shí)現(xiàn)。因此,信號(hào)注冊(cè)與否,與本節(jié)后面講到的發(fā)送信號(hào)函數(shù)(如kill()等)以及信號(hào)安裝函數(shù)(如signal()等)無(wú)關(guān),只與信號(hào)值有關(guān)。

用戶進(jìn)程對(duì)信號(hào)的響應(yīng)可以有3種方式。

n 忽略信號(hào),即對(duì)信號(hào)不做任何處理,但是有兩個(gè)信號(hào)不能忽略,即SIGKILL及SIGSTOP。

n 捕捉信號(hào),定義信號(hào)處理函數(shù),當(dāng)信號(hào)發(fā)生時(shí),執(zhí)行相應(yīng)的自定義處理函數(shù)。

n 執(zhí)行缺省操作,Linux對(duì)每種信號(hào)都規(guī)定了默認(rèn)操作。

Linux中的大多數(shù)信號(hào)是提供給內(nèi)核的,表8.6列出了Linux中最為常見(jiàn)信號(hào)的含義及其默認(rèn)操作。

表8.6 常見(jiàn)信號(hào)的含義及其默認(rèn)操作

信號(hào)名

含義

默認(rèn)操作

SIGHUP

該信號(hào)在用戶終端連接(正?;蚍钦#┙Y(jié)束時(shí)發(fā)出,通常是在終端的控制進(jìn)程結(jié)束時(shí),通知同一會(huì)話內(nèi)的各個(gè)作業(yè)與控制終端不再關(guān)聯(lián)

終止

SIGINT

該信號(hào)在用戶鍵入INTR字符(通常是Ctrl-C)時(shí)發(fā)出,終端驅(qū)動(dòng)程序發(fā)送此信號(hào)并送到前臺(tái)進(jìn)程中的每一個(gè)進(jìn)程

終止

SIGQUIT

該信號(hào)和SIGINT類似,但由QUIT字符(通常是Ctrl-)來(lái)控制

終止

SIGILL

該信號(hào)在一個(gè)進(jìn)程企圖執(zhí)行一條非法指令時(shí)(可執(zhí)行文件本身出現(xiàn)錯(cuò)誤,或者試圖執(zhí)行數(shù)據(jù)段、堆棧溢出時(shí))發(fā)出

終止

SIGFPE

該信號(hào)在發(fā)生致命的算術(shù)運(yùn)算錯(cuò)誤時(shí)發(fā)出。這里不僅包括浮點(diǎn)運(yùn)算錯(cuò)誤,還包括溢出及除數(shù)為0等其他所有的算術(shù)錯(cuò)誤

終止

SIGKILL

該信號(hào)用來(lái)立即結(jié)束程序的運(yùn)行,并且不能被阻塞、處理或忽略

終止

SIGALRM

該信號(hào)當(dāng)一個(gè)定時(shí)器到時(shí)的時(shí)候發(fā)出

終止

SIGSTOP

該信號(hào)用于暫停一個(gè)進(jìn)程,且不能被阻塞、處理或忽略

暫停進(jìn)程

SIGTSTP

該信號(hào)用于交互停止進(jìn)程,用戶鍵入SUSP字符時(shí)(通常是Ctrl+Z)發(fā)出這個(gè)信號(hào)

停止進(jìn)程

SIGCHLD

子進(jìn)程改變狀態(tài)時(shí),父進(jìn)程會(huì)收到這個(gè)信號(hào)

忽略

SIGABORT

進(jìn)程異常終止時(shí)發(fā)出

8.3.2信號(hào)發(fā)送與捕捉

發(fā)送信號(hào)的函數(shù)主要有kill()、raise()、alarm()以及pause(),下面就依次對(duì)其進(jìn)行介紹。

1.kill()和raise()

(1)函數(shù)說(shuō)明。

kill()函數(shù)同讀者熟知的kill系統(tǒng)命令一樣,可以發(fā)送信號(hào)給進(jìn)程或進(jìn)程組(實(shí)際上,kill系統(tǒng)命令只是kill()函數(shù)的一個(gè)用戶接口)。這里需要注意的是,它不僅可以中止進(jìn)程(實(shí)際上發(fā)出SIGKILL信號(hào)),也可以向進(jìn)程發(fā)送其他信號(hào)。

與kill()函數(shù)所不同的是,raise()函數(shù)允許進(jìn)程向自身發(fā)送信號(hào)。

(2)函數(shù)格式。

表8.7列出了kill()函數(shù)的語(yǔ)法要點(diǎn)。

表8.7 kill()函數(shù)語(yǔ)法要點(diǎn)

所需頭文件

#include<signal.h>
#include<sys/types.h>

函數(shù)原型

intkill(pid_tpid,intsig)

函數(shù)傳入值

pid:

正數(shù):要發(fā)送信號(hào)的進(jìn)程號(hào)

0:信號(hào)被發(fā)送到所有和當(dāng)前進(jìn)程在同一個(gè)進(jìn)程組的進(jìn)程

-1:信號(hào)發(fā)給所有的進(jìn)程表中的進(jìn)程(除了進(jìn)程號(hào)最大的進(jìn)程外)

<-1:信號(hào)發(fā)送給進(jìn)程組號(hào)為-pid的每一個(gè)進(jìn)程

sig:信號(hào)

函數(shù)返回值

成功:0

出錯(cuò):-1

表8.8列出了raise()函數(shù)的語(yǔ)法要點(diǎn)。

表8.8 raise()函數(shù)語(yǔ)法要點(diǎn)

所需頭文件

#include<signal.h>
#include<sys/types.h>

函數(shù)原型

intraise(intsig)

函數(shù)傳入值

sig:信號(hào)

函數(shù)返回值

成功:0

出錯(cuò):-1

(3)函數(shù)實(shí)例。

下面這個(gè)示例首先使用fork()創(chuàng)建了一個(gè)子進(jìn)程,接著為了保證子進(jìn)程不在父進(jìn)程調(diào)用kill()之前退出,在子進(jìn)程中使用raise()函數(shù)向自身發(fā)送SIGSTOP信號(hào),使子進(jìn)程暫停。接下來(lái)再在父進(jìn)程中調(diào)用kill()向子進(jìn)程發(fā)送信號(hào),在該示例中使用的是SIGKILL,讀者可以使用其他信號(hào)進(jìn)行練習(xí)。

/*kill_raise.c*/

#include<stdio.h>

#include<stdlib.h>

#include<signal.h>

#include<sys/types.h>

#include<sys/wait.h>

intmain()

{

pid_tpid;

intret;

/*創(chuàng)建一子進(jìn)程*/

if((pid=fork())<0)

{

printf("Forkerrorn");

exit(1);

}

if(pid==0)

{

/*在子進(jìn)程中使用raise()函數(shù)發(fā)出SIGSTOP信號(hào),使子進(jìn)程暫停*/

printf("Child(pid:%d)iswaitingforanysignaln",getpid());

raise(SIGSTOP);

exit(0);

}

else

{

/*在父進(jìn)程中收集子進(jìn)程發(fā)出的信號(hào),并調(diào)用kill()函數(shù)進(jìn)行相應(yīng)的操作*/

if((waitpid(pid,NULL,WNOHANG))==0)

{

if((ret=kill(pid,SIGKILL))==0)

{

printf("Parentkill%dn",pid);

}

}

waitpid(pid,NULL,0);

exit(0);

}

}

該程序運(yùn)行結(jié)果如下所示:

$./kill_raise

Child(pid:4877)iswaitingforanysignal

Parentkill4877

2.a(chǎn)larm()和pause()

(1)函數(shù)說(shuō)明。

alarm()也稱為鬧鐘函數(shù),它可以在進(jìn)程中設(shè)置一個(gè)定時(shí)器,當(dāng)定時(shí)器指定的時(shí)間到時(shí),它就向進(jìn)程發(fā)送SIGALARM信號(hào)。要注意的是,一個(gè)進(jìn)程只能有一個(gè)鬧鐘時(shí)間,如果在調(diào)用alarm()之前已設(shè)置過(guò)鬧鐘時(shí)間,則任何以前的鬧鐘時(shí)間都被新值所代替。

pause()函數(shù)是用于將調(diào)用進(jìn)程掛起直至捕捉到信號(hào)為止。這個(gè)函數(shù)很常用,通??梢杂糜谂袛嘈盘?hào)是否已到。

(2)函數(shù)格式。

表8.9列出了alarm()函數(shù)的語(yǔ)法要點(diǎn)。

表8.9 alarm()函數(shù)語(yǔ)法要點(diǎn)

所需頭文件

#include<unistd.h>

函數(shù)原型

unsignedintalarm(unsignedintseconds)

函數(shù)傳入值

seconds:指定秒數(shù),系統(tǒng)經(jīng)過(guò)seconds秒之后向該進(jìn)程發(fā)送SIGALRM信號(hào)

函數(shù)返回值

成功:如果調(diào)用此alarm()前,進(jìn)程中已經(jīng)設(shè)置了鬧鐘時(shí)間,則返回上一個(gè)鬧鐘時(shí)間的剩余時(shí)間,否則返回0

出錯(cuò):-1

表8.10列出了pause()函數(shù)的語(yǔ)法要點(diǎn)。

表8.10 pause()函數(shù)語(yǔ)法要點(diǎn)

所需頭文件

#include<unistd.h>

函數(shù)原型

intpause(void)

函數(shù)返回值

-1,并且把error值設(shè)為EINTR

(3)函數(shù)實(shí)例。

該實(shí)例實(shí)際上已完成了一個(gè)簡(jiǎn)單的sleep()函數(shù)的功能,由于SIGALARM默認(rèn)的系統(tǒng)動(dòng)作為終止該進(jìn)程,因此程序在打印信息之前,就會(huì)被結(jié)束了。代碼如下所示:

/*alarm_pause.c*/

#include<unistd.h>

#include<stdio.h>

#include<stdlib.h>

intmain()

{

/*調(diào)用alarm定時(shí)器函數(shù)*/

intret=alarm(5);

pause();

printf("Ihavebeenwakenup.n",ret);/*此語(yǔ)句不會(huì)被執(zhí)行*/

}

$./alarm_pause

Alarmclock

想一想

用這種形式實(shí)現(xiàn)的sleep()功能有什么問(wèn)題?

8.3.3信號(hào)的處理

在了解了信號(hào)的產(chǎn)生與捕獲之后,接下來(lái)就要對(duì)信號(hào)進(jìn)行具體的操作了。從前面的信號(hào)概述中讀者也可以看到,特定的信號(hào)是與一定的進(jìn)程相聯(lián)系的。也就是說(shuō),一個(gè)進(jìn)程可以決定在該進(jìn)程中需要對(duì)哪些信號(hào)進(jìn)行什么樣的處理。例如,一個(gè)進(jìn)程可以選擇忽略某些信號(hào)而只處理其他一些信號(hào),另外,一個(gè)進(jìn)程還可以選擇如何處理信號(hào)??傊?,這些都是與特定的進(jìn)程相聯(lián)系的。因此,首先就要建立進(jìn)程與其信號(hào)之間的對(duì)應(yīng)關(guān)系,這就是信號(hào)的處理。

注意

請(qǐng)讀者注意信號(hào)的注冊(cè)與信號(hào)的處理之間的區(qū)別,前者信號(hào)是主動(dòng)方,而后者進(jìn)程是主動(dòng)方。信號(hào)的注冊(cè)是在進(jìn)程選擇了特定信號(hào)處理之后特定信號(hào)的主動(dòng)行為。

信號(hào)處理的主要方法有兩種,一種是使用簡(jiǎn)單的signal()函數(shù),另一種是使用信號(hào)集函數(shù)組。下面分別介紹這兩種處理方式。

1.信號(hào)處理函數(shù)

(1)函數(shù)說(shuō)明。

使用signal()函數(shù)處理時(shí),只需要指出要處理的信號(hào)和處理函數(shù)即可。它主要是用于前32種非實(shí)時(shí)信號(hào)的處理,不支持信號(hào)傳遞信息,但是由于使用簡(jiǎn)單、易于理解,因此也受到很多程序員的歡迎。

Linux還支持一個(gè)更健壯、更新的信號(hào)處理函數(shù)sigaction(),推薦使用該函數(shù)。

(2)函數(shù)格式。

signal()函數(shù)的語(yǔ)法要點(diǎn)如表8.11所示。

表8.11 signal()函數(shù)語(yǔ)法要點(diǎn)

所需頭文件

#include<signal.h>

函數(shù)原型

void(*signal(intsignum,void(*handler)(int)))(int)

函數(shù)傳入值

signum:指定信號(hào)代碼

handler:

SIG_IGN:忽略該信號(hào)

SIG_DFL:采用系統(tǒng)默認(rèn)方式處理信號(hào)

自定義的信號(hào)處理函數(shù)指針

函數(shù)返回值

成功:以前的信號(hào)處理配置

出錯(cuò):-1

這里需要對(duì)這個(gè)函數(shù)原型進(jìn)行說(shuō)明。這個(gè)函數(shù)原型有點(diǎn)復(fù)雜??上扔萌缦碌膖ypedef進(jìn)行替換說(shuō)明:

typedefvoidsign(int);

sign*signal(int,handler*);

可見(jiàn),首先該函數(shù)原型整體指向一個(gè)無(wú)返回值并且?guī)б粋€(gè)整型參數(shù)的函數(shù)指針,也就是信號(hào)的原始配置函數(shù)。接著該原型又帶有兩個(gè)參數(shù),其中的第二個(gè)參數(shù)可以是用戶自定義的信號(hào)處理函數(shù)的函數(shù)指針。

表8.12列舉了sigaction()的語(yǔ)法要點(diǎn)。

表8.12 sigaction()函數(shù)語(yǔ)法要點(diǎn)

所需頭文件

#include<signal.h>

函數(shù)原型

intsigaction(intsignum,conststructsigaction*act,structsigaction*oldact)

函數(shù)傳入值

signum:信號(hào)代碼,可以為除SIGKILL及SIGSTOP外的任何一個(gè)特定有效的信號(hào)

act:指向結(jié)構(gòu)sigaction的一個(gè)實(shí)例的指針,指定對(duì)特定信號(hào)的處理

oldact:保存原來(lái)對(duì)相應(yīng)信號(hào)的處理

函數(shù)返回值

成功:0

出錯(cuò):-1

這里要說(shuō)明的是sigaction()函數(shù)中第2個(gè)和第3個(gè)參數(shù)用到的sigaction結(jié)構(gòu)。這是一個(gè)看似非常復(fù)雜的結(jié)構(gòu),希望讀者能夠慢慢閱讀此段內(nèi)容。

首先給出了sigaction的定義,如下所示:

structsigaction

{

void(*sa_handler)(intsigno);

sigset_tsa_mask;

intsa_flags;

void(*sa_restore)(void);

}

sa_handler是一個(gè)函數(shù)指針,指定信號(hào)處理函數(shù),這里除可以是用戶自定義的處理函數(shù)外,還可以為SIG_DFL(采用缺省的處理方式)或SIG_IGN(忽略信號(hào))。它的處理函數(shù)只有一個(gè)參數(shù),即信號(hào)值。

sa_mask是一個(gè)信號(hào)集,它可以指定在信號(hào)處理程序執(zhí)行過(guò)程中哪些信號(hào)應(yīng)當(dāng)被屏蔽,在調(diào)用信號(hào)捕獲函數(shù)之前,該信號(hào)集要加入到信號(hào)的信號(hào)屏蔽字中。

sa_flags中包含了許多標(biāo)志位,是對(duì)信號(hào)進(jìn)行處理的各個(gè)選擇項(xiàng)。它的常見(jiàn)可選值如表8.13所示。

表8.13 常見(jiàn)信號(hào)的含義及其默認(rèn)操作

選項(xiàng)

含義

SA_NODEFERSA_NOMASK

當(dāng)捕捉到此信號(hào)時(shí),在執(zhí)行其信號(hào)捕捉函數(shù)時(shí),系統(tǒng)不會(huì)自動(dòng)屏蔽此信號(hào)

SA_NOCLDSTOP

進(jìn)程忽略子進(jìn)程產(chǎn)生的任何SIGSTOP、SIGTSTP、SIGTTIN和SIGTTOU信號(hào)

SA_RESTART

令重啟的系統(tǒng)調(diào)用起作用

SA_ONESHOTSA_RESETHAND

自定義信號(hào)只執(zhí)行一次,在執(zhí)行完畢后恢復(fù)信號(hào)的系統(tǒng)默認(rèn)動(dòng)作

(3)使用實(shí)例。

第一個(gè)實(shí)例表明了如何使用signal()函數(shù)捕捉相應(yīng)信號(hào),并做出給定的處理。這里,my_func就是信號(hào)處理的函數(shù)指針。讀者還可以將其改為SIG_IGN或SIG_DFL查看運(yùn)行結(jié)果。第二個(gè)實(shí)例是用sigaction()函數(shù)實(shí)現(xiàn)同樣的功能。

以下是使用signal()函數(shù)的示例:

/*signal.c*/

#include<signal.h>

#include<stdio.h>

#include<stdlib.h>

/*自定義信號(hào)處理函數(shù)*/

voidmy_func(intsign_no)

{

if(sign_no==SIGINT)

{

printf("IhavegetSIGINTn");

}

elseif(sign_no==SIGQUIT)

{

printf("IhavegetSIGQUITn");

}

}

intmain()

{

printf("WaitingforsignalSIGINTorSIGQUIT...n");

/*發(fā)出相應(yīng)的信號(hào),并跳轉(zhuǎn)到信號(hào)處理函數(shù)處*/

signal(SIGINT,my_func);

signal(SIGQUIT,my_func);

pause();

exit(0);

}

運(yùn)行結(jié)果如下所示。

$./signal

WaitingforsignalSIGINTorSIGQUIT...

IhavegetSIGINT(按ctrl-c組合鍵)

$./signal

WaitingforsignalSIGINTorSIGQUIT...

IhavegetSIGQUIT(按ctrl-組合鍵)

以下是用sigaction()函數(shù)實(shí)現(xiàn)同樣的功能,下面只列出更新的main()函數(shù)部分。

/*sigaction.c*/

/*前部分省略*/

intmain()

{

structsigactionaction;

printf("WaitingforsignalSIGINTorSIGQUIT...n");

/*sigaction結(jié)構(gòu)初始化*/

action.sa_handler=my_func;

sigemptyset(&action.sa_mask);

action.sa_flags=0;

/*發(fā)出相應(yīng)的信號(hào),并跳轉(zhuǎn)到信號(hào)處理函數(shù)處*/

sigaction(SIGINT,&action,0);

sigaction(SIGQUIT,&action,0);

pause();

exit(0);

}

2.信號(hào)集函數(shù)組

(1)函數(shù)說(shuō)明。

使用信號(hào)集函數(shù)組處理信號(hào)時(shí)涉及一系列的函數(shù),這些函數(shù)按照調(diào)用的先后次序可分為以下幾大功能模塊:創(chuàng)建信號(hào)集合、注冊(cè)信號(hào)處理函數(shù)以及檢測(cè)信號(hào)。

其中,創(chuàng)建信號(hào)集合主要用于處理用戶感興趣的一些信號(hào),其函數(shù)包括以下幾個(gè)。

n sigemptyset():將信號(hào)集合初始化為空。

n sigfillset():將信號(hào)集合初始化為包含所有已定義的信號(hào)的集合。

n sigaddset():將指定信號(hào)加入到信號(hào)集合中去。

n sigdelset():將指定信號(hào)從信號(hào)集合中刪除。

n sigismember():查詢指定信號(hào)是否在信號(hào)集合之中。

注冊(cè)信號(hào)處理函數(shù)主要用于決定進(jìn)程如何處理信號(hào)。這里要注意的是,信號(hào)集里的信號(hào)并不是真正可以處理的信號(hào),只有當(dāng)信號(hào)的狀態(tài)處于非阻塞狀態(tài)時(shí)才會(huì)真正起作用。因此,首先使用sigprocmask()函數(shù)檢測(cè)并更改信號(hào)屏蔽字(信號(hào)屏蔽字是用來(lái)指定當(dāng)前被阻塞的一組信號(hào),它們不會(huì)被進(jìn)程接收),然后使用sigaction()函數(shù)來(lái)定義進(jìn)程接收到特定信號(hào)之后的行為。檢測(cè)信號(hào)是信號(hào)處理的后續(xù)步驟,因?yàn)楸蛔枞男盘?hào)不會(huì)傳遞給進(jìn)程,所以這些信號(hào)就處于“未處理”狀態(tài)(也就是進(jìn)程不清楚它的存在)。sigpending()函數(shù)允許進(jìn)程檢測(cè)“未處理”信號(hào),并進(jìn)一步?jīng)Q定對(duì)它們作何處理。

(2)函數(shù)格式。

首先介紹創(chuàng)建信號(hào)集合的函數(shù)格式,表8.14列舉了這一組函數(shù)的語(yǔ)法要點(diǎn)。

表8.14 創(chuàng)建信號(hào)集合函數(shù)語(yǔ)法要點(diǎn)

所需頭文件

#include<signal.h>

函數(shù)原型

intsigemptyset(sigset_t*set)

intsigfillset(sigset_t*set)

intsigaddset(sigset_t*set,intsignum)

intsigdelset(sigset_t*set,intsignum)

intsigismember(sigset_t*set,intsignum)

函數(shù)傳入值

set:信號(hào)集

signum:指定信號(hào)代碼

函數(shù)返回值

成功:0(sigismember成功返回1,失敗返回0)

出錯(cuò):-1

表8.15列舉了sigprocmask的語(yǔ)法要點(diǎn)。

表8.15 sigprocmask函數(shù)語(yǔ)法要點(diǎn)

所需頭文件

#include<signal.h>

函數(shù)原型

intsigprocmask(inthow,constsigset_t*set,sigset_t*oset)

函數(shù)傳入值

how:決定函數(shù)的操作方式

SIG_BLOCK:增加一個(gè)信號(hào)集合到當(dāng)前進(jìn)程的阻塞集合之中

SIG_UNBLOCK:從當(dāng)前的阻塞集合之中刪除一個(gè)信號(hào)集合

SIG_SETMASK:將當(dāng)前的信號(hào)集合設(shè)置為信號(hào)阻塞集合

set:指定信號(hào)集

oset:信號(hào)屏蔽字

函數(shù)返回值

成功:0

出錯(cuò):-1

此處,若set是一個(gè)非空指針,則參數(shù)how表示函數(shù)的操作方式;若how為空,則表示忽略此操作。

最后,表8.16列舉了sigpending函數(shù)的語(yǔ)法要點(diǎn)。

表8.16 sigpending函數(shù)語(yǔ)法要點(diǎn)

所需頭文件

#include<signal.h>

函數(shù)原型

intsigpending(sigset_t*set)

函數(shù)傳入值

set:要檢測(cè)的信號(hào)集

函數(shù)返回值

成功:0

出錯(cuò):-1

總之,在處理信號(hào)時(shí),一般遵循如圖8.7所示的操作流程。

圖8.7一般的信號(hào)操作處理流程

(3)使用實(shí)例。

該實(shí)例首先把SIGQUIT、SIGINT兩個(gè)信號(hào)加入信號(hào)集,然后將該信號(hào)集合設(shè)為阻塞狀態(tài),并進(jìn)入用戶輸入狀態(tài)。用戶只需按任意鍵,就可以立刻將信號(hào)集合設(shè)置為非阻塞狀態(tài),再對(duì)這兩個(gè)信號(hào)分別操作,其中SIGQUIT執(zhí)行默認(rèn)操作,而SIGINT執(zhí)行用戶自定義函數(shù)的操作。源代碼如下所示:

/*sigset.c*/

#include<sys/types.h>

#include<unistd.h>

#include<signal.h>

#include<stdio.h>

#include<stdlib.h>

/*自定義的信號(hào)處理函數(shù)*/

voidmy_func(intsignum)

{

printf("Ifyouwanttoquit,pleasetrySIGQUITn");

}

intmain()

{

sigset_tset,pendset;

structsigactionaction1,action2;

/*初始化信號(hào)集為空*/

if(sigemptyset(&set)<0)

{

perror("sigemptyset");

exit(1);

}

/*將相應(yīng)的信號(hào)加入信號(hào)集*/

if(sigaddset(&set,SIGQUIT)<0)

{

perror("sigaddset");

exit(1);

}

if(sigaddset(&set,SIGINT)<0)

{

perror("sigaddset");

exit(1);

}

if(sigismember(&set,SIGINT))

{

sigemptyset(&action1.sa_mask);

action1.sa_handler=my_func;

action1.sa_flags=0;

sigaction(SIGINT,&action1,NULL);

}

if(sigismember(&set,SIGQUIT))

{

sigemptyset(&action2.sa_mask);

action2.sa_handler=SIG_DFL;

action2.sa_flags=0;

sigaction(SIGQUIT,&action2,NULL);

}

/*設(shè)置信號(hào)集屏蔽字,此時(shí)set中的信號(hào)不會(huì)被傳遞給進(jìn)程,暫時(shí)進(jìn)入待處理狀態(tài)*/

if(sigprocmask(SIG_BLOCK,&set,NULL)<0)

{

perror("sigprocmask");

exit(1);

}

else

{

printf("Signalsetwasblocked,Pressanykey!");

getchar();

}

/*在信號(hào)屏蔽字中刪除set中的信號(hào)*/

if(sigprocmask(SIG_UNBLOCK,&set,NULL)<0)

{

perror("sigprocmask");

exit(1);

}

else

{

printf("Signalsetisinunblockstaten");

}

while(1);

exit(0);

}

該程序的運(yùn)行結(jié)果如下所示,可以看見(jiàn),在信號(hào)處于阻塞狀態(tài)時(shí),所發(fā)出的信號(hào)對(duì)進(jìn)程不起作用,并且該信號(hào)進(jìn)入待處理狀態(tài)。讀者輸入任意鍵,并且信號(hào)脫離了阻塞狀態(tài)之后,用戶發(fā)出的信號(hào)才能正常運(yùn)行。這里SIGINT已按照用戶自定義的函數(shù)運(yùn)行,請(qǐng)讀者注意阻塞狀態(tài)下SIGINT的處理和非阻塞狀態(tài)下SIGINT的處理有何不同。

$./sigset

Signalsetwasblocked,Pressanykey!/*此時(shí)按任何鍵可以解除阻塞屏蔽字*/

Ifyouwanttoquit,pleasetrySIGQUIT/*阻塞狀態(tài)下SIGINT的處理*/

Signalsetisinunblockstate/*從信號(hào)屏蔽字中刪除set中的信號(hào)*/

Ifyouwanttoquit,pleasetrySIGQUIT/*非阻塞狀態(tài)下SIGINT的處理*/

Ifyouwanttoquit,pleasetrySIGQUIT

Quit/*非阻塞狀態(tài)下SIGQUIT處理*/

本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點(diǎn),本站亦不保證或承諾內(nèi)容真實(shí)性等。需要轉(zhuǎn)載請(qǐng)聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請(qǐng)及時(shí)聯(lián)系本站刪除。
換一批
延伸閱讀

LED驅(qū)動(dòng)電源的輸入包括高壓工頻交流(即市電)、低壓直流、高壓直流、低壓高頻交流(如電子變壓器的輸出)等。

關(guān)鍵字: 驅(qū)動(dòng)電源

在工業(yè)自動(dòng)化蓬勃發(fā)展的當(dāng)下,工業(yè)電機(jī)作為核心動(dòng)力設(shè)備,其驅(qū)動(dòng)電源的性能直接關(guān)系到整個(gè)系統(tǒng)的穩(wěn)定性和可靠性。其中,反電動(dòng)勢(shì)抑制與過(guò)流保護(hù)是驅(qū)動(dòng)電源設(shè)計(jì)中至關(guān)重要的兩個(gè)環(huán)節(jié),集成化方案的設(shè)計(jì)成為提升電機(jī)驅(qū)動(dòng)性能的關(guān)鍵。

關(guān)鍵字: 工業(yè)電機(jī) 驅(qū)動(dòng)電源

LED 驅(qū)動(dòng)電源作為 LED 照明系統(tǒng)的 “心臟”,其穩(wěn)定性直接決定了整個(gè)照明設(shè)備的使用壽命。然而,在實(shí)際應(yīng)用中,LED 驅(qū)動(dòng)電源易損壞的問(wèn)題卻十分常見(jiàn),不僅增加了維護(hù)成本,還影響了用戶體驗(yàn)。要解決這一問(wèn)題,需從設(shè)計(jì)、生...

關(guān)鍵字: 驅(qū)動(dòng)電源 照明系統(tǒng) 散熱

根據(jù)LED驅(qū)動(dòng)電源的公式,電感內(nèi)電流波動(dòng)大小和電感值成反比,輸出紋波和輸出電容值成反比。所以加大電感值和輸出電容值可以減小紋波。

關(guān)鍵字: LED 設(shè)計(jì) 驅(qū)動(dòng)電源

電動(dòng)汽車(EV)作為新能源汽車的重要代表,正逐漸成為全球汽車產(chǎn)業(yè)的重要發(fā)展方向。電動(dòng)汽車的核心技術(shù)之一是電機(jī)驅(qū)動(dòng)控制系統(tǒng),而絕緣柵雙極型晶體管(IGBT)作為電機(jī)驅(qū)動(dòng)系統(tǒng)中的關(guān)鍵元件,其性能直接影響到電動(dòng)汽車的動(dòng)力性能和...

關(guān)鍵字: 電動(dòng)汽車 新能源 驅(qū)動(dòng)電源

在現(xiàn)代城市建設(shè)中,街道及停車場(chǎng)照明作為基礎(chǔ)設(shè)施的重要組成部分,其質(zhì)量和效率直接關(guān)系到城市的公共安全、居民生活質(zhì)量和能源利用效率。隨著科技的進(jìn)步,高亮度白光發(fā)光二極管(LED)因其獨(dú)特的優(yōu)勢(shì)逐漸取代傳統(tǒng)光源,成為大功率區(qū)域...

關(guān)鍵字: 發(fā)光二極管 驅(qū)動(dòng)電源 LED

LED通用照明設(shè)計(jì)工程師會(huì)遇到許多挑戰(zhàn),如功率密度、功率因數(shù)校正(PFC)、空間受限和可靠性等。

關(guān)鍵字: LED 驅(qū)動(dòng)電源 功率因數(shù)校正

在LED照明技術(shù)日益普及的今天,LED驅(qū)動(dòng)電源的電磁干擾(EMI)問(wèn)題成為了一個(gè)不可忽視的挑戰(zhàn)。電磁干擾不僅會(huì)影響LED燈具的正常工作,還可能對(duì)周圍電子設(shè)備造成不利影響,甚至引發(fā)系統(tǒng)故障。因此,采取有效的硬件措施來(lái)解決L...

關(guān)鍵字: LED照明技術(shù) 電磁干擾 驅(qū)動(dòng)電源

開(kāi)關(guān)電源具有效率高的特性,而且開(kāi)關(guān)電源的變壓器體積比串聯(lián)穩(wěn)壓型電源的要小得多,電源電路比較整潔,整機(jī)重量也有所下降,所以,現(xiàn)在的LED驅(qū)動(dòng)電源

關(guān)鍵字: LED 驅(qū)動(dòng)電源 開(kāi)關(guān)電源

LED驅(qū)動(dòng)電源是把電源供應(yīng)轉(zhuǎn)換為特定的電壓電流以驅(qū)動(dòng)LED發(fā)光的電壓轉(zhuǎn)換器,通常情況下:LED驅(qū)動(dòng)電源的輸入包括高壓工頻交流(即市電)、低壓直流、高壓直流、低壓高頻交流(如電子變壓器的輸出)等。

關(guān)鍵字: LED 隧道燈 驅(qū)動(dòng)電源
關(guān)閉