Linux中的signal是一種異步處通信機制,信號類型分為可靠信號和非可靠信號兩種。所謂非可靠信號是linux繼承unix的編號從1至31號信號,是用作特殊用處;可靠信號即linux中新添加的編號從34至64的信號,此類信號可以用戶自定義使用。
由于linux的signal機制也經過了一系列的改造,因此我們就拿現在的signal機制來分析一下signal的使用。
一、信號的發送
信號的產生方式有多種,可能是用戶程序使用相關函數進行發送,也可能是用戶通過外部輸入通知內核來產生信號等等。我們就那用戶程序來說明一下用戶空間信號的發送。
1)進程中:
int kill(pid_t pid, int sig);
int raise(int sig);
kill函數來給對應的進程發送信號。其中pid參數有三種類型:
pid 大于0時,就是給PID為pid的進程發送sig信號。
Pid 等于0時, 就是給和當前進程在同一進程組的所有進程發送sig信號。
Pid 等于-1時,會給所有有權限發送的進程發送sig信號,除了init進程。
父進程殺死子進程的示例代碼:
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函數就是進程給自己發送信號。
比如: raise(SIGKILL);就是進程的自殺信號。
2)線程的信號發送
int pthread_kill(pthread_t thread, int sig);
參數pthread_t就是指定要發送的線程標識符,sig就是要送的信號。
如果給線程發送的信號的默認處理方式是終止進程,那么也會導致進程直接退出。
比如:
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信號,那么會導致整個進程也立刻退出。
二、信號的捕捉處理
常用的信號捕捉處理函數有兩個。
1)signal函數
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
參數 signum就是signal函數要捕捉的信號,參數handler就是對捕捉信號的處理函數。
示例代碼:讓程序在執行過程中不受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 : 對信號處理的結構體
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);
};
igaction函數的功能要比signal函數要強大,但是使用也比較復雜。
示例代碼:
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);
}
…….
}