關於 信號signal的知識鋪墊 點這裡
信號由三種處理方式:
如果信號的處理動作是用戶自定義函數,在信號遞達時就調用這個自定義函數,這稱為捕捉信號。
進程收到一個信號後不會被立即處理,而是在恰當時機進行處理!即內核態返回用戶態之前 !
但是由於信號處理函數的代碼在用戶空間,所以這增加了內核處理信號捕捉的復雜度。
給某一個進程的某一個信號(標號為signum)注冊一個相應的處理函數,即對該信號的默認處理動作進行修改,修改為handler函數指向的方式;
1 2 3#include <signal.h>
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);<br>
//
即:<br>void (*signal(int, void(*)(int)))(int);
signal函數接受兩個參數:一個整型的信號編號,以及一個指向用戶定義的信號處理函數的指針。
此外,signal函數的返回值是一個指向調用用戶定義信號處理函數的指針。
sigaction函數可以讀取和修改與指定信號相關聯的處理動作。
1 2 3 4 5 6 7 8 9 10#include <signal.h>
int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
struct sigaction
{
void (*sa_handler)(int);
//
信號處理方式
void (*sa_sigaction)(int, siginfo_t *, void *);
//
實時信號的處理方式 暫不討論
sigset_t sa_mask;
//
額外屏蔽的信號
int sa_flags;
void (*sa_restorer)(void);
};
signum是指定信號的編號。
處理方式:
(注:後兩個參數都是輸入輸出型參數!)
將sa_handler三種可選方式:
(注:這是一個回調函數,不是被main函數調用,而是被系統所調用)
當某個信號的處理函數被調用時,內核自動將當前信號加入進程的信號屏蔽字,當信號處理函數返回時自動恢復原來的信號屏蔽字,這樣就保證了在處理某個信號時,如果這種信號再次產生,那麼 它會被阻塞到當前處理結束為止。
pause函數使調用進程掛起直到有信號遞達!
1 2#include <unistd.h>
int pause(void);
處理方式:
所以pause只有出錯的返回值(類似exec函數家族)。錯誤碼EINTR表示“被信號中斷”。
進入sig_alrm函數時SIGALRM信號被自動屏蔽,從sig_alrm函數返回時SIGALRM信號自動解除屏蔽。然後自動執行特殊的系統調用sigreturn再次進入內核,之後再返回用戶態繼續執行進程的主控制流程(main函數調用的mytest函數)。
pause函數返回-1,然後調用alarm(0)取消鬧鐘,調用sigaction恢復SIGALRM信號以前的處理 動作。
/*************************************************************************
> File Name: Pause.c
> Author:Lynn-Zhang
> Mail: [email protected]
> Created Time: Sun 14 Aug 2016 12:27:03 PM CST
************************************************************************/
#include<stdio.h>
#include<signal.h>
#include<unistd.h>
void sig_alarm(int signum)
{
printf
(
"I am a custom handler!\n"
);
}
void mysleep(unsigned int
times
)
{
//
注冊兩個信號處理動作
struct sigaction new,old;
new.sa_handler=sig_alarm;
//
信號處理函數
sigemptyset(&new.sa_mask);
//
不屏蔽任何信號屏蔽字
new.sa_flags=0;
//
對SIGALRM 信號的默認處理動作修改為自定義處理動作
sigaction(SIGALRM,&new,&old);
alarm(
times
);
pause();
//
掛起等待
alarm(1);
sleep
(2);
alarm(0);
//
取消鬧鐘
//
恢復SIGALRM 信號到默認處理動作
sigaction(SIGALRM,&old,NULL);
alarm(1);
sleep
(2);
}
int main()
{
while
(1)
{
mysleep(2);
printf
(
"many seconds passed\n"
);
printf
(
"###################\n"
);
}
return
0;
}
定義一個鬧鐘並掛起等待,收到信號後執行自定義處理動作,在沒有恢復默認處理動作前,收到SIGALRM信號都會按照其自定義處理函數來處理。恢復自定義處理動作之後收到SIGALRM信號則執行其默認處理動作即終止進程!