對Llinux下(xia)signal機制的(de)一(yi)點認(ren)識
時(shi)間:2018-09-20 來源(yuan):未(wei)知
Linux中的(de)signal是一(yi)種異步處通信(xin)機(ji)制,信(xin)號(hao)類型(xing)分(fen)為可(ke)靠信(xin)號(hao)和非(fei)可(ke)靠信(xin)號(hao)兩種。所(suo)謂非(fei)可(ke)靠信(xin)號(hao)是linux繼承unix的(de)編(bian)號(hao)從1至(zhi)31號(hao)信(xin)號(hao),是用(yong)(yong)作特殊用(yong)(yong)處;可(ke)靠信(xin)號(hao)即linux中新添(tian)加的(de)編(bian)號(hao)從34至(zhi)64的(de)信(xin)號(hao),此(ci)類信(xin)號(hao)可(ke)以用(yong)(yong)戶自定義使用(yong)(yong)。
由于linux的signal機制(zhi)也經過了一系列的改造,因此我們(men)就拿現(xian)在(zai)的signal機制(zhi)來分析一下signal的使用。
一、信號的發送
信(xin)號(hao)的(de)產(chan)生方式有多種(zhong),可能(neng)是(shi)用戶(hu)(hu)程(cheng)序使用相(xiang)關函數進行發(fa)(fa)送(song),也可能(neng)是(shi)用戶(hu)(hu)通(tong)過外部(bu)輸入通(tong)知(zhi)內(nei)核來產(chan)生信(xin)號(hao)等等。我們就那(nei)用戶(hu)(hu)程(cheng)序來說明一下用戶(hu)(hu)空(kong)間信(xin)號(hao)的(de)發(fa)(fa)送(song)。
1)進(jin)程(cheng)中:
int kill(pid_t pid, int sig);
int raise(int sig);
kill函(han)數(shu)來給對應的進程(cheng)發送信號。其(qi)中pid參數(shu)有(you)三(san)種類型:
pid 大(da)于0時,就是給PID為(wei)pid的進程發送(song)sig信號。
Pid 等于0時, 就是(shi)給和當前(qian)進程(cheng)在同(tong)一(yi)進程(cheng)組的所有進程(cheng)發送(song)sig信號。
Pid 等(deng)于-1時,會給(gei)所有有權(quan)限發送(song)的進(jin)程發送(song)sig信號(hao),除(chu)了init進(jin)程。
父進程(cheng)殺死子進程(cheng)的示(shi)例代碼:
Pid = fork();
If (pid == 0)
{
Printf(“in the child process\n”);
While (1);
}
else if (pid > 0)
{
Printf(“in the parent process\n”);
Kill(getpid(), SIGKILL);
Wait(NULL);
}
return 0;
raise函(han)數就(jiu)是進程給自己(ji)發送信(xin)號(hao)。
比如: raise(SIGKILL);就是進程(cheng)的自殺(sha)信號。
2)線程(cheng)的信號發送
int pthread_kill(pthread_t thread, int sig);
參(can)數pthread_t就是指定要(yao)(yao)發(fa)送(song)的線程標識符(fu),sig就是要(yao)(yao)送(song)的信號。
如果給(gei)線程發(fa)送(song)的信號的默(mo)認處理(li)方式是(shi)終止進(jin)程,那么(me)也會導致進(jin)程直接(jie)退出。
比如:
pthread_t thread1, thread2;
void handler1(void *arg);
void handler2(void*arg);
Int main(int argc, const char*argv[])
{
pthread_create(&thread1, NULL, handler1, NULL);
pthread_create(&thread2, NULL, handler2, NULL);
pthread_join(thread1, NULL);
pthread_join(thread2, NULL);
}
void handler1(void *arg)
{
While (1);
}
void handler2(void *arg)
{
pthread_kill(thread1, SIGKILL);
pthread_exit(0);
}
線程2一旦發送SIGKILL信號,那么會導致(zhi)整(zheng)個(ge)進程也立(li)刻退出。
二、信號的捕捉處理
常(chang)用的信號捕捉處理(li)函數有兩個。
1)signal函數(shu)
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
參(can)數 signum就是signal函數要捕捉的信號(hao),參(can)數handler就是對捕捉信號(hao)的處理函數。
示例代碼:讓程(cheng)序在執行(xing)過程(cheng)中不受crtl + C的影響
void handler(int signo)
{
printf(“SIGINT is ignore\n”);
}
Int main()
{
….
signal(SIGINT, handler);
….
}
2) sigaction函數
int sigaction (int signum, const struct sigaction *act, struct sigaction *oldact);
參數signum: 要捕捉的信號
act : 對信號處(chu)理的結構(gou)體
oldact: 用來(lai)保存舊的信號(hao)處(chu)理(li)方式的結構體
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);
};
igaction函數的功能要(yao)比signal函數要(yao)強大,但是使用(yong)也比較復雜。
示例代碼:
void handler(int signo)
{
printf(“SIGINT is ignore\n”);
}
Int main()
{
struct sigaction new, old;
new.sa_handler = handler;
sigemptyset(&new.sa_mask);
new.sa_flags = 0;
sigaction(SIGINT, NULL, &old);
if (old.sa_handler != SIG_IGN)
{
sigaction(SIGINT, &new, NULL);
}
…….
}

