您好,登錄后才能下訂單哦!
我們接著談Linux學習過程中一個重要的話題--信號。
一、信號的概念:
信號是一種軟件中斷,它提供了一種處理異步事件的方法,也是進程間唯一的異步通信方式。
二、信號的來源:
1、硬件方式:
當用戶按下終端上某些鍵時,將產生信號。
硬件異常產生信號:除0操作、訪問非法空間……
2、軟件方式
用戶在終端下調用kill命令向進程發送任意信號
進程調用kill或者sigqueue函數發送信號。
當檢測到某種軟件條件發生時,如alarm或者setimer
三、信號處理
1、信號的捕捉和處理
1、signal函數
a、函數作用:
signal函數用來設置進程在接收到信號時的動作。
b、函數原型:
#include <signal.h> typedef void (*sighandler_t)(int); sighandler_t signal(int signum, sighandler_t handler);
c、參數解析與函數說明:
signal函數會根據參數signal指定的信號編號來設置該信號的處理函數。當指定的信號到達時就會
跳到參數hander指定的函數執行。如果hander不是函數指針,則必須時常數SIG_IGN忽略該信號)或者S
IG_DFL(對該信號執行默認操作)。hander是 一個函數指針,它所指向的函數的類型時sighandel_t,即
它 所指向的函數有一個int型參數,且返回值的類型為void。
d、樣這里給出signal處理信號的例子:
/********************************************************** * > 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> //信號處理函數 void do_sig(int num) { printf("I am do_sig\n"); } int main() { //安裝處理信號 signal(SIGINT,do_sig); while(1) { printf("********\n"); sleep(1); } return 0; }
2、sigaction函數
a、函數作用:
sigction函數可以用來檢查和設置進程在接收信號時的動作。
b、函數原型
#include <signal.h>
int sigaction(int signum, const struct sigaction *act,
struct sigaction *oldact);
c、參數解析與函數說明:
sigzction函數會根據參數signum指定的信號編號來設置該信號的處理函數。參數signum可以是除了
SIGKILLh和SIGSTOP以外的任何信號。
如果參數act 不是空指針,則為signum設置新的信號處理函數;
如果oldzct不是空指針,則舊的信號處理函數將被存儲在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可以是常數SIG_DFL或者SIG_IGN,或者是一個信號處理函數名。
sa_sigaction也是用來指定信號的signum的處理函數。
sa_mask成員聲明了一個信號集,在調用信號捕捉函數之前,該信號會增加到進程的信號屏蔽碼中,
新的信號屏蔽碼會自動包括正在處理的信號(sa_flags未指定SA_NODEFER或者SA_NOMASK)。當從信號捕
捉函數返回時,進程的信號屏蔽碼會恢復為原來的值。因此,當處理一個給定的 信號時,如果這種
信號再次發生,那么它會阻塞直到本次信號處理結束為止。若這種信號發生了多次,則對于不可靠信號,
即本次信號處理結束以后只會再次處理一次(相當于丟失了信號),對于可靠信號(實時信號),則會
被阻塞多次,即信號不會丟失,信號發生了多少次就會調用信號處理函數多少次。
sa_flags成員用來說明信號處理的其他相關操作。
當使用三參數的sa_sigaction來指定信號處理函數時,它的第 二個參數可以用來傳遞數據,其定義
如下:
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的測試用例
/********************************************************** * > 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; //信號處理函數 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; //結構體賦值 act.sa_handler = do_sigact; act.sa_flags = SA_NOMASK; //安裝信號處理函數 sigaction(SIGINT,&act,NULL); while(1) { printf("********************\n"); sleep(1); } return 0; }
編寫信號處理函數時,要注意不要使用不可重入的函數,使用了不重入的函數將將產生不可預料的結果。
上邊就是sigaction函數的基本用法,復雜的用法后邊使用。
補充:滿足下列條件的函數是不可重入的:
a、使用了靜態的數據結構,如getgrpid(),全局變量等。
b、函數實現時,調用了malloc()或者free()函數。
c、函數實現時,使用了標準I/O函數。
3、pause()函數
a、函數作用:
pause函數使調用進程掛起直到捕捉到一個信號。pause函數會令目前的進程暫停(進入睡眠狀態),
直到被信號(signal)所中斷,該函數只返回-1,并將errno設置為EINTR。
b、函數原型:
#include <unistd.h>
int pause(void);
四、信號的發送:
信號的發送主要由函數kill、raise、sigqueue、alarm、setitimer以及 abort來完成。
1、kill函數
a、函數作用:
kill函數用來發送信號給指定的進程。
b、函數原型
#include <sys/types.h> #include <signal.h> int kill(pid_t pid, int sig);
c、參數解析與函數說明:
該函數的行為與第二個參數pid的取值有關,第二個參數sig表示信號編號:
如果pid時正數,則發送信號sig給進程號為pid的進程;
果pid為0,則發送信號sig給當前進程所屬進程組里的所有進程;
如果pid為-1,則把信號sig廣播給系統內的除1號進程和自身以外的所有進程;
如果pid為比-1還小的負數,則發送信號sig給屬于進程組-pid的所有進程;
如果參數sig是0,則kill(),仍然執行正常的錯誤檢查,但不發送信號。可以利用這一點來確定某
進程是否有權向另外一個進程發送信號。如果向一個并不存在的進程發送空信號,則kill()返回-1,
errno則被設置為ESRCH。
注意:只有具有root權限的進程才能向其他任意一個進程發送信號,非root權限的進程只能向屬于同一
個組成或者同一個用戶創建的進程發送信號。
2、raise函數
a、函數作用:
raise函數是ANSI C 而非POSIX標準定義的。用來給調用它的進程發送信號。
b、函數原型
#include <signal.h> int raise(int sig);
3、sigqueue函數
a、函數作用
sigqueue函數是一個比較新的發送信號的函數,它支持信號帶有參數,從而可以與函數sigaction配
合使用。
b、函數原型
#include <signal.h>
int sigqueue(pid_t pid, int sig, const union sigval value);
c、參數解析與函數說明:
sigqueue用來發送給信號sig給進程pid。與kill系統調用不同的是,sigqueue在發送信號的同時
還支持信號攜帶參數;另外一個不同點是sigqueue 不能給一組進程發送信號,參數value是一個共用
體,其定義如下:
union sigval {
int sival_int;
void *sival_ptr;
};
4、alarm函數
a、函數作用
alarm函數可以用來設置定時器,定時器超時將產生SIGALRM信號給調用進程。
b、函數原型
#include <unistd.h> unsigned int alarm(unsigned int seconds);
c、參數解析與函數說明:
參數seconds表示設定的秒數,經過seconds后,內核將給調用該函數的進程發送SIGALRM信號。如果seconds為0,
則不再發送SIGALRM信號,最新一次調用alarm函數將取消之前一次的設定。
5、abrot函數
a、函數作用:
abrot函數用來向進程發送SIGABRT信號。
b、函數原型
#include <stdlib.h> void abort(void)
上邊我只對信號的基本用法做了總結,后邊將對信號的高級用法做單獨總結。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。