我們接著談Linux學(xué)習(xí)過(guò)程中一個(gè)重要的話題--信號(hào)。
讓客戶滿意是我們工作的目標(biāo),不斷超越客戶的期望值來(lái)自于我們對(duì)這個(gè)行業(yè)的熱愛(ài)。我們立志把好的技術(shù)通過(guò)有效、簡(jiǎn)單的方式提供給客戶,將通過(guò)不懈努力成為客戶在信息化領(lǐng)域值得信任、有價(jià)值的長(zhǎng)期合作伙伴,公司提供的服務(wù)項(xiàng)目有:主機(jī)域名、網(wǎng)絡(luò)空間、營(yíng)銷軟件、網(wǎng)站建設(shè)、勐臘網(wǎng)站維護(hù)、網(wǎng)站推廣。
一、信號(hào)的概念:
信號(hào)是一種軟件中斷,它提供了一種處理異步事件的方法,也是進(jìn)程間唯一的異步通信方式。
二、信號(hào)的來(lái)源:
1、硬件方式:
當(dāng)用戶按下終端上某些鍵時(shí),將產(chǎn)生信號(hào)。
硬件異常產(chǎn)生信號(hào):除0操作、訪問(wèn)非法空間……
2、軟件方式
用戶在終端下調(diào)用kill命令向進(jìn)程發(fā)送任意信號(hào)
進(jìn)程調(diào)用kill或者sigqueue函數(shù)發(fā)送信號(hào)。
當(dāng)檢測(cè)到某種軟件條件發(fā)生時(shí),如alarm或者setimer
三、信號(hào)處理
1、信號(hào)的捕捉和處理
1、signal函數(shù)
a、函數(shù)作用:
signal函數(shù)用來(lái)設(shè)置進(jìn)程在接收到信號(hào)時(shí)的動(dòng)作。
b、函數(shù)原型:
#include <signal.h> typedef void (*sighandler_t)(int); sighandler_t signal(int signum, sighandler_t handler);
c、參數(shù)解析與函數(shù)說(shuō)明:
signal函數(shù)會(huì)根據(jù)參數(shù)signal指定的信號(hào)編號(hào)來(lái)設(shè)置該信號(hào)的處理函數(shù)。當(dāng)指定的信號(hào)到達(dá)時(shí)就會(huì)
跳到參數(shù)hander指定的函數(shù)執(zhí)行。如果hander不是函數(shù)指針,則必須時(shí)常數(shù)SIG_IGN忽略該信號(hào))或者S
IG_DFL(對(duì)該信號(hào)執(zhí)行默認(rèn)操作)。hander是 一個(gè)函數(shù)指針,它所指向的函數(shù)的類型時(shí)sighandel_t,即
它 所指向的函數(shù)有一個(gè)int型參數(shù),且返回值的類型為void。
d、樣這里給出signal處理信號(hào)的例子:
/********************************************************** * > File Name: signal-1.c * > Author:xiao_k * > Mail:18629086235@163.com * > Created Time: Fri 23 Feb 2018 12:05:46 AM CST **********************************************************/ #include<stdlib.h> #include<stdio.h> #include<unistd.h> #include<errno.h> #include<string.h> #include<signal.h> //信號(hào)處理函數(shù) void do_sig(int num) { printf("I am do_sig\n"); } int main() { //安裝處理信號(hào) signal(SIGINT,do_sig); while(1) { printf("********\n"); sleep(1); } return 0; }
2、sigaction函數(shù)
a、函數(shù)作用:
sigction函數(shù)可以用來(lái)檢查和設(shè)置進(jìn)程在接收信號(hào)時(shí)的動(dòng)作。
b、函數(shù)原型
#include <signal.h>
int sigaction(int signum, const struct sigaction *act,
struct sigaction *oldact);
c、參數(shù)解析與函數(shù)說(shuō)明:
sigzction函數(shù)會(huì)根據(jù)參數(shù)signum指定的信號(hào)編號(hào)來(lái)設(shè)置該信號(hào)的處理函數(shù)。參數(shù)signum可以是除了
SIGKILLh和SIGSTOP以外的任何信號(hào)。
如果參數(shù)act 不是空指針,則為signum設(shè)置新的信號(hào)處理函數(shù);
如果oldzct不是空指針,則舊的信號(hào)處理函數(shù)將被存儲(chǔ)在oldact中,struct sigaction的定義如下:
struct sigaction {
void (*sa_handler)(int);
void (*sa_sigaction)(int, siginfo_t *, void *);
sigset_t sa_mask;
int sa_flags;
void (*sa_restorer)(void);
};
sa_handler可以是常數(shù)SIG_DFL或者SIG_IGN,或者是一個(gè)信號(hào)處理函數(shù)名。
sa_sigaction也是用來(lái)指定信號(hào)的signum的處理函數(shù)。
sa_mask成員聲明了一個(gè)信號(hào)集,在調(diào)用信號(hào)捕捉函數(shù)之前,該信號(hào)會(huì)增加到進(jìn)程的信號(hào)屏蔽碼中,
新的信號(hào)屏蔽碼會(huì)自動(dòng)包括正在處理的信號(hào)(sa_flags未指定SA_NODEFER或者SA_NOMASK)。當(dāng)從信號(hào)捕
捉函數(shù)返回時(shí),進(jìn)程的信號(hào)屏蔽碼會(huì)恢復(fù)為原來(lái)的值。因此,當(dāng)處理一個(gè)給定的 信號(hào)時(shí),如果這種
信號(hào)再次發(fā)生,那么它會(huì)阻塞直到本次信號(hào)處理結(jié)束為止。若這種信號(hào)發(fā)生了多次,則對(duì)于不可靠信號(hào),
即本次信號(hào)處理結(jié)束以后只會(huì)再次處理一次(相當(dāng)于丟失了信號(hào)),對(duì)于可靠信號(hào)(實(shí)時(shí)信號(hào)),則會(huì)
被阻塞多次,即信號(hào)不會(huì)丟失,信號(hào)發(fā)生了多少次就會(huì)調(diào)用信號(hào)處理函數(shù)多少次。
sa_flags成員用來(lái)說(shuō)明信號(hào)處理的其他相關(guān)操作。
當(dāng)使用三參數(shù)的sa_sigaction來(lái)指定信號(hào)處理函數(shù)時(shí),它的第 二個(gè)參數(shù)可以用來(lái)傳遞數(shù)據(jù),其定義
如下:
siginfo_t {
int si_signo; /* Signal number */
int si_errno; /* An errno value */
int si_code; /* Signal code */
int si_trapno; /* Trap number that caused
hardware-generated signal (unused on most architectures) */
pid_t si_pid; /* Sending process ID */
uid_t si_uid; /* Real user ID of sending process */
int si_status; /* Exit value or signal */
clock_t si_utime; /* User time consumed */
clock_t si_stime; /* System time consumed */
sigval_t si_value; /* Signal value */
int si_int; /* POSIX.1b signal */
void *si_ptr; /* POSIX.1b signal */
int si_overrun; /* Timer overrun count;POSIX.1b timers */
int si_timerid; /* Timer ID; POSIX.1b timers */
void *si_addr; /* Memory location which caused fault */
int si_band; /* Band event */
int si_fd; /* File descriptor */
}
d、同樣給出 sigaction的測(cè)試用例
/********************************************************** * > File Name: sigaction-1.c * > Author:xiao_k * > Mail:18629086235@163.com * > Created Time: Fri 23 Feb 2018 01:47:43 AM CST **********************************************************/ #include<stdio.h> #include<stdlib.h> #include<unistd.h> #include<errno.h> #include<signal.h> int temp = 0; //信號(hào)處理函數(shù) void do_sigact(int num) { printf("recv SIGINT\n"); sleep(5); temp +=1; printf("the value of temp is :%d\n",temp); printf("in do_sigact,after sleep\n"); } int main() { struct sigaction act; //結(jié)構(gòu)體賦值 act.sa_handler = do_sigact; act.sa_flags = SA_NOMASK; //安裝信號(hào)處理函數(shù) sigaction(SIGINT,&act,NULL); while(1) { printf("********************\n"); sleep(1); } return 0; }
編寫信號(hào)處理函數(shù)時(shí),要注意不要使用不可重入的函數(shù),使用了不重入的函數(shù)將將產(chǎn)生不可預(yù)料的結(jié)果。
上邊就是sigaction函數(shù)的基本用法,復(fù)雜的用法后邊使用。
補(bǔ)充:滿足下列條件的函數(shù)是不可重入的:
a、使用了靜態(tài)的數(shù)據(jù)結(jié)構(gòu),如getgrpid(),全局變量等。
b、函數(shù)實(shí)現(xiàn)時(shí),調(diào)用了malloc()或者free()函數(shù)。
c、函數(shù)實(shí)現(xiàn)時(shí),使用了標(biāo)準(zhǔn)I/O函數(shù)。
3、pause()函數(shù)
a、函數(shù)作用:
pause函數(shù)使調(diào)用進(jìn)程掛起直到捕捉到一個(gè)信號(hào)。pause函數(shù)會(huì)令目前的進(jìn)程暫停(進(jìn)入睡眠狀態(tài)),
直到被信號(hào)(signal)所中斷,該函數(shù)只返回-1,并將errno設(shè)置為EINTR。
b、函數(shù)原型:
#include <unistd.h>
int pause(void);
四、信號(hào)的發(fā)送:
信號(hào)的發(fā)送主要由函數(shù)kill、raise、sigqueue、alarm、setitimer以及 abort來(lái)完成。
1、kill函數(shù)
a、函數(shù)作用:
kill函數(shù)用來(lái)發(fā)送信號(hào)給指定的進(jìn)程。
b、函數(shù)原型
#include <sys/types.h> #include <signal.h> int kill(pid_t pid, int sig);
c、參數(shù)解析與函數(shù)說(shuō)明:
該函數(shù)的行為與第二個(gè)參數(shù)pid的取值有關(guān),第二個(gè)參數(shù)sig表示信號(hào)編號(hào):
如果pid時(shí)正數(shù),則發(fā)送信號(hào)sig給進(jìn)程號(hào)為pid的進(jìn)程;
果pid為0,則發(fā)送信號(hào)sig給當(dāng)前進(jìn)程所屬進(jìn)程組里的所有進(jìn)程;
如果pid為-1,則把信號(hào)sig廣播給系統(tǒng)內(nèi)的除1號(hào)進(jìn)程和自身以外的所有進(jìn)程;
如果pid為比-1還小的負(fù)數(shù),則發(fā)送信號(hào)sig給屬于進(jìn)程組-pid的所有進(jìn)程;
如果參數(shù)sig是0,則kill(),仍然執(zhí)行正常的錯(cuò)誤檢查,但不發(fā)送信號(hào)??梢岳眠@一點(diǎn)來(lái)確定某
進(jìn)程是否有權(quán)向另外一個(gè)進(jìn)程發(fā)送信號(hào)。如果向一個(gè)并不存在的進(jìn)程發(fā)送空信號(hào),則kill()返回-1,
errno則被設(shè)置為ESRCH。
注意:只有具有root權(quán)限的進(jìn)程才能向其他任意一個(gè)進(jìn)程發(fā)送信號(hào),非root權(quán)限的進(jìn)程只能向?qū)儆谕?/p>
個(gè)組成或者同一個(gè)用戶創(chuàng)建的進(jìn)程發(fā)送信號(hào)。
2、raise函數(shù)
a、函數(shù)作用:
raise函數(shù)是ANSI C 而非POSIX標(biāo)準(zhǔn)定義的。用來(lái)給調(diào)用它的進(jìn)程發(fā)送信號(hào)。
b、函數(shù)原型
#include <signal.h> int raise(int sig);
3、sigqueue函數(shù)
a、函數(shù)作用
sigqueue函數(shù)是一個(gè)比較新的發(fā)送信號(hào)的函數(shù),它支持信號(hào)帶有參數(shù),從而可以與函數(shù)sigaction配
合使用。
b、函數(shù)原型
#include <signal.h>
int sigqueue(pid_t pid, int sig, const union sigval value);
c、參數(shù)解析與函數(shù)說(shuō)明:
sigqueue用來(lái)發(fā)送給信號(hào)sig給進(jìn)程pid。與kill系統(tǒng)調(diào)用不同的是,sigqueue在發(fā)送信號(hào)的同時(shí)
還支持信號(hào)攜帶參數(shù);另外一個(gè)不同點(diǎn)是sigqueue 不能給一組進(jìn)程發(fā)送信號(hào),參數(shù)value是一個(gè)共用
體,其定義如下:
union sigval {
int sival_int;
void *sival_ptr;
};
4、alarm函數(shù)
a、函數(shù)作用
alarm函數(shù)可以用來(lái)設(shè)置定時(shí)器,定時(shí)器超時(shí)將產(chǎn)生SIGALRM信號(hào)給調(diào)用進(jìn)程。
b、函數(shù)原型
#include <unistd.h> unsigned int alarm(unsigned int seconds);
c、參數(shù)解析與函數(shù)說(shuō)明:
參數(shù)seconds表示設(shè)定的秒數(shù),經(jīng)過(guò)seconds后,內(nèi)核將給調(diào)用該函數(shù)的進(jìn)程發(fā)送SIGALRM信號(hào)。如果seconds為0,
則不再發(fā)送SIGALRM信號(hào),最新一次調(diào)用alarm函數(shù)將取消之前一次的設(shè)定。
5、abrot函數(shù)
a、函數(shù)作用:
abrot函數(shù)用來(lái)向進(jìn)程發(fā)送SIGABRT信號(hào)。
b、函數(shù)原型
#include <stdlib.h> void abort(void)
上邊我只對(duì)信號(hào)的基本用法做了總結(jié),后邊將對(duì)信號(hào)的高級(jí)用法做單獨(dú)總結(jié)。
本文標(biāo)題:Linux系統(tǒng)編程之進(jìn)程間通信之淺談信號(hào)
標(biāo)題來(lái)源:http://jinyejixie.com/article20/ggedco.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供電子商務(wù)、響應(yīng)式網(wǎng)站、網(wǎng)站建設(shè)、軟件開發(fā)、域名注冊(cè)、服務(wù)器托管
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)