1. 程式人生 > >Linux 對信號的總結

Linux 對信號的總結

lock 哪些 結構 nds 進程 博客 unsigned 同時 eas

Linux信號_總結

對信號本質的理解:

類似於中斷,區別在於中斷是由硬件產生的,而信號是由軟件實現的。

信號的來源:

觸發硬件(觸發鍵盤,或是硬件故障);軟件信號函數kill 、alarm、setitimer、sigqueue 等函數。

信號的分類:

可靠信號與不可靠信號,實時信號與非實時信號;

不可靠信號:

SIGRTMIN前的信號稱為不可靠信號,在早期這段信號可能做出錯誤的反應,或是丟失。因此對此段信號成為不可靠信號。

可靠信號:

在SIGRTMIN與SIGRTMAX之間的信號稱做可靠信號,可靠信號是為了防止信號丟失的。這些信號可以排隊處理。

實時信號與非實時信號:

非實時信號都不支持排隊,都是不可靠信號;實時信號都是支持排隊的,都是可靠信號;

對信號的響應:

響應的三種方式

(1)忽略信號

有兩個特殊的信號SIGKILL 和SIGSTOP信號不能被忽略。

(2)捕捉信號

給對應的信號綁定響應的處理函數,帶到信號產生時,執行對應的函數。

(3)執行缺省信號

進程對實時信號的缺省反應時進程的終止。

信號的發送:

發送信號的函數有,kill(), alarm(),raise(),setitimer();

(1)kill(int pid, int signal);

PID參數信號的就收進程
pid>0 進程的ID為pid的進程
pid=0 同一個進程組
pid<0 && pid!=-1 進程組ID為pid絕對值的所有進程
pid=-1 發送至所有ID大於1的進程

參數介紹:

pid為進程號,singnal為信號值。

kill常用於pid>0的信號處理,調用成功返回0,否則返回-1。

(2)alarm(unsigned int seconds)

專門為SIGALRM信號而設函數,seconds表示時間,此函數意味著在seconds秒後向SIGALRM信號發送消息。

進程調用alarm後,以前的alarm()調用都將無效。若調用alarm()前,進程中已經設置了鬧鐘,則返回上一個鬧鐘生於的時間,否則返回0;

eg:

#include<signal.h>
#include<stdio.h>
int main(void)
{
printf("first time return:%d\n",alarm(4));
sleep(1);
printf("after sleep(1),remain:%d\n",alarm(2));
printf("renew alarm,remain:%d\n",alarm(1));
}
?
//運行結果為
first time return:0
after sleep(1),remain:3
renew alarm,remain:2
?

(3)raise(int signal);

此函數時向本進程發送signal信號的,signal為即將發送的信號值。調用成功返回0;否則返回 -1。

(4)setitimer()函數

int setitimer(int which, const struct itimerval *value, struct itimerval *ovalue));

結構體介紹:

struct itimerval 
{
 struct timeval it_interval;//間隔時間
 struct timeval it_value; //初始時間
 };
?
struct timeval
{
long tv_sec; //秒
long tv_usec; //微妙
};

參數描述:

which:表示定時器類型,setitimer有三種定時器類型。

ITIMER_REAL : 以系統真實的時間來計算,它送出SIGALRM信號。  

ITIMER_VIRTUAL : 設定程序執行時間;經過指定的時間後,內核將發送SIGVTALRM信號給本進程;

ITIMER_PROF : 設定進程執行以及內核因本進程而消耗的時間和,經過指定的時間後,內核將發送ITIMER_VIRTUAL信號給本進程;

it_interval指定間隔時間,it_value指定初始定時時間。如果只指定it_value,就是實現一次定時;如果同時指定 it_interval,則超時後,系統會重新初始化it_value為it_interval,實現重復定時;

eg:

#include <signal.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/time.h>
?
void sigroutine(int signo) {
switch (signo) {
case SIGALRM:
printf("Catch a signal -- SIGALRM\n");
break;
case SIGVTALRM:
printf("Catch a signal -- SIGVTALRM\n");
break;
}
}
?
int main(int argc, char ** argv) {
struct itimerval value,ovalue,value2;
?
printf("process id is %d\n",getpid());
signal(SIGALRM, sigroutine); //為SIGALRM信號綁定sigroutine函數
signal(SIGVTALRM, sigroutine); //為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 (;;) ;
}
?
//運行結果為
process id is 3136
Catch a signal -- SIGVTALRM
Catch a signal -- SIGALRM
Catch a signal -- SIGVTALRM
Catch a signal -- SIGVTALRM
Catch a signal -- SIGALRM
Catch a signal -- SIGVTALRM
Catch a signal -- SIGVTALRM
Catch a signal -- SIGALRM
Catch a signal -- SIGVTALRM
Catch a signal -- SIGVTALRM
Catch a signal -- SIGALRM
Catch a signal -- SIGVTALRM
Catch a signal -- SIGVTALRM
Catch a signal -- SIGALRM
Catch a signal -- SIGVTALRM
Catch a signal -- SIGVTALRM
Catch a signal -- SIGALRM
Catch a signal -- SIGVTALRM
Catch a signal -- SIGVTALRM
?

安裝信號:

由signal()、sigaction()處理:

(1)signal(int signum, sighandler_t handler);

此函數的作用是,為handler函數,或處理過程綁定一個信號,每當出現信號後,進行handler處理。

signum:所指信號;

handler:處理過程,可以時函數的指針。這個也可設置為"SIG_IGN",表示忽略此信號,"SIG_DFL"表示以系統默認方式處理此信號。(註意:SIGKILL SIGSTOP不可被安裝)

此函數的例子可參考上一個例子。

(2)sigaction();

int sigaction(int signum,const struct sigaction *act,struct sigaction *oldact));

signum:指定的信號(除SIGKILL,SIGSTOP外)

sigaction:指向結構指針,指定對特定信號的處理

oldact:指向的對象用來保存原來對相應信號的處理

sigaction()函數中第二個參數最為關鍵。

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);
};
?

(1)結構體中的sa_restorer已經不使用可以忽略。

(2)sa_handler指定的處理函數只有一個參數類似於使用signal()函數

(3)sa_sigaction也是指定信號的處理函數,不過可以帶三個參數:

第一個參數為信號值;

第二個參數是指向siginfo_t結構的指針;

第三個參數沒有使用;

siginfo_t結構體如下:

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 */
long si_band; /* Band event (was int in
glibc 2.3.2 and earlier) */
int si_fd; /* File descriptor */
short si_addr_lsb; /* Least significant bit of address
(since Linux 2.6.32) */
};

(4)sa_mask指定在信號處理程序執行過程中,哪些信號應當被阻塞。缺省情況下當前信號本身被阻塞,防止信號的嵌套發送,除非指定SA_NODEFER或者SA_NOMASK標誌位。

註:請註意sa_mask指定的信號阻塞的前提條件,是在由sigaction()安裝信號的處理函數執行過程中由sa_mask指定的信號才被阻塞。

(5)sa_flags標誌位:

當sa_flags設置為SA_SIGINFO時,示信號附帶的參數可以傳遞到信號處理函數中。即使sa_sigaction指定信號處理函數,如果不設置SA_SIGINFO,信號處理函數同樣不能得到信號傳遞過來的數據,在信號處理函數中對這些信息的訪問都將導致段錯誤。

信號,介紹先到此,如若覺得又不對的地方,請指出,共同進步謝謝!

參考博客有:

https://www.ibm.com/developerworks/cn/linux/l-ipc/part2/index1.html

http://www.cnblogs.com/dandingyy/articles/2653218.html

Linux 對信號的總結