每個信號都有一個編號和一個宏定義名稱 ,這些宏定義可以在 signal.h 中找到。
使用kill -l命令查看系統中定義的信號列表: 1-31是普通信號; 34-64是實時信號 所有的信號都由操作系統來發!#include <signal.h>
typedef
void
( *sighandler_t)(
int
);
sighandler_t
signal
(
int
signum, sighandler_t handler);
signal函數的作用:給某一個進程的某一個特定信號(標號為signum)注冊一個相應的處理函數,即對該信號的默認處理動作進行修改,修改為handler函數所指向的方式。
舉個代碼例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17#include<stdio.h>
#include<signal.h>
void
handler(
int
sig)
{
printf
(
"get a sig,num is %d\n"
,sig);
}
int
main()
{
signal
(2,handler);
while
(1)
{
sleep(1);
printf
(
"hello\n"
);
}
return
0;
}
修改了2號信號(Ctrl-c)的默認處理動作為handler函數的內容,則當該程序在前台運行時,鍵入Ctrl-c後不會執行它的默認處理動作(終止該進程)
進程收到一個信號後不會被立即處理,而是在恰當 時機進行處理!什麼是適當的時候呢?比如說中斷返回的時候,或者內核態返回用戶態的時候(這個情況出現的比較多)。
信號不一定會被立即處理,操作系統不會為了處理一個信號而把當前正在運行的進程掛起(切換進程),掛起(進程切換)的話消耗太大了,如果不是緊急信號,是不會立即處理的。操作系統多選擇在內核態切換回用戶態的時候處理信號,這樣就利用兩者的切換來處理了(不用單獨進行進程切換以免浪費時間)。
總歸是不能避免的,因為很有可能在睡眠的進程就接收到信號,操作系統肯定不願意切換當前正在運行的進程,於是就得把信號儲存在進程唯一的PCB(task_struct)當中。
/*************************************************************************
> File Name:
test
.c
> Author:Lynn-Zhang
> Mail: [email protected]
> Created Time: Fri 15 Jul 2016 03:03:57 PM CST
************************************************************************/
#include<stdio.h>
int main()
{
printf
(
"get pid :%d circle ...\n"
,getpid());
while
(1);
return
0;
}
寫一個上面的程序在後台執行死循環,並獲取該進程的id,然後用kill命令給它發送SIGSEGV信號,可以使進程終止。也可以使用kill -11 5796,11是信號SIGSEGV的編號。
打開終端1,運行程序:
利用終端2,給進程發送信號
終端1 顯示進程被core了:
kill命令是調用kill函數實現的。kill函數可以給一個指定的進程發送指定信號。
raise函數可 以給當前進程發送指定的信號 (自己給自己發信號 )
1 2 3#include<signal.h>
int
kill(pid_t pid,
int
signo);
int
raise
(
int
signo);
這兩個函數都是成功返回0,錯誤返回-1.
除此之外,abort函數使當前進程接收到SIGABRT信號而異常終止。
1
2
#include<stdlib.h>
void
abort
(
void
);
就像 exit函數一樣 ,abort 函數總是會成功的 ,所以沒有返回值。
3.由軟件條件產生信號
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/*************************************************************************
> File Name: alarm.c
> Author:Lynn-Zhang
> Mail: [email protected]
> Created Time: Fri 15 Jul 2016 08:52:02 PM CST
************************************************************************/
#include<stdio.h>
int
main()
{
int
count=0;
alarm(1);
while
(1)
{
printf
(
"%d\n"
,count);
count++;
}
return
0;
}
通過實現以上代碼,調用alarm函數可以設定一個鬧鐘,告訴內核在seconds秒之後給當前進程發SIGALRM信號, 該信號的默認處理動作是終止當前進程。
該程序會在1秒鐘之內不停地數數,並打印計數器,1秒鐘到了就被SIGALRM信號終止。由於電腦配置等的不同,每台電腦一秒鐘之內計數值是不同的一般是不同的。
1 2#include <unistd.h>
unsigned
int
alarm(unsigned
int
seconds);
alarm函數的返回值是0或上次設置鬧鐘剩余的時間。