1、什麼是信號
1.1、信號是內容受限的一種異步通信機制
(1)信號的目的:用來通信
(2)信號是異步的(對比硬件中斷)
(3)信號本質上是int型數字編號(事先定義好的)
1.2、信號由誰發出
(1)用戶在終端按下按鍵
(2)硬件異常後由操作系統內核發出信號
(3)用戶使用kill命令向其他進程發出信號
(4)某種軟件條件滿足後也會發出信號,如alarm鬧鐘時間到會產生SIGALRM信號,向一個讀端已經關閉的管道write時會產生SIGPIPE信號。
1.3、信號處理方式
(1)忽略信號
(2)捕獲信號(信號綁定了一個函數)
(3)默認處理(當前進程沒有明顯的管這個信號,默認:忽略或終止進程)
2、常見信號介紹
(1)SIGINT 2 Ctrl+C時OS發送給前臺進程組中每個進程
(2)SIGABRT 6 調用abort函數,進程異常終止
(3)SIGPOLL SIGIO 8 指示一個異步IO事件,在高級IO中體積
(4)SIGKILL 9 殺死進程的終極方法
(5)SIGSEGV 11 無效存儲訪問時OS發出該信號
(6)SIGPIPE 13 涉及管道和socket
(7)SIGALRM 14 涉及alarm函數的實現
(8)SIGTERM 15 kill命令發送的OS默認終止信號
(9)SIGCHLD 17 子進程終止或停止時OS向其父進程發送此信號
(10)
SIGUSR1 10 用戶自定義信號,作用和意義由應用自己定義
SIGUSR2 12
3、進程對信號的處理
3.1、signal函數
3.2、用signal函數處理SIGINT信號
(1)默認處理
(2)忽略處理
(3)捕獲處理
細節:
(1)signal函數綁定一個捕獲函數後,信號發生後會自動執行綁定的捕獲函數,並且把信號編號作爲傳參傳給捕獲函數。
(2)signal的返回值在出錯時爲SIG_ERR,綁定成功時返回舊的捕獲函數。
3.3、signal函數的優點和缺點
(1)優點:簡單好用,捕獲信號常用
(2)缺點:無法簡單直接得知之前設置的對信號的處理方法
3.4、sigaction函數介紹
(1)2個都是API,但是sigaction比signal更具有可移植性
(2)用法關鍵是2個sigaction指針
編程實例:
/*
*功能描述:
*將SIGINT 2 Ctrl+C時OS發送給前臺進程組中每個進程,即“CTRL + C”功能重綁定到捕獲函數func
*重綁定信號捕獲函數func之後,
*當在終端按下“CTRL + C”時,不再執行OS發送給前臺進程組中每個進程,即終止當前進程的功能
*而是去執行用戶自定義的信號捕獲函數func中的內容
*要想結束當前進程,在linux系統中,先使用“ps -ajx”查看當前進程的進程號,記爲xxx
*最後,用“kill -9 xxx”結束該進程。
*/
#include <stdio.h>
#include <signal.h>
#include <errno.h>
// typedef void (*sighandler_t)(int);
void func(int sig)
{
if(SIGINT != sig)
{
perror("signal");
return;
}
printf("func for signal: %d.\n", sig);
}
int main(void)
{
// sighandler_t ret = (sighandler_t)-2;
signal(SIGINT, func);
//signal(SIGINT, SIG_DFL); //指定信號SIGINT爲默認處理
//signal(SIGINT, SIG_IGN); //指定信號SIG_IGN爲忽略處理
printf("before while(1)\n");
while(1);
printf("after while(1)\n");
return 0;
}
4、alarm和pause函數
4.1、alarm函數
(1)內核以API形式提供的鬧鐘
4.2、pause函數
(1)內核掛起
pause函數的作用就是讓當前進程暫停運行,交出CPU給其它進程去執行。噹噹前進程進入pause狀態後,當前進程會表現爲“卡住、阻塞住”,要退出pause狀態,當前進程需要被信號喚醒。
編程實例:
/*
*功能描述:測試sigaction()、alarm()函數和pause()函數的使用
*1、使用sigaction()函數綁定一個捕獲函數func
*2、使用alarm()函數設置一個發送信號的鬧鐘,發送的信號爲SIGALRM
*3、使用pause()掛起當前進程,當前進程等待alarm信號發生被喚醒執行func函數
*/
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
void func(int sig)
{
if(SIGALRM == sig)
{
printf("alarm happened!\n");
}
}
int main(void)
{
unsigned int ret = 0;
struct sigaction act = {0};
act.sa_handler = func;
sigaction(SIGALRM, &act, NULL);
//signal(SIGALRM, func);
ret = alarm(5); //5s 設置一個發送信號的鬧鐘
printf("1st,ret = %d.\n", ret);
sleep(3);
ret = alarm(5); //5s
printf("2st,ret = %d.\n", ret);
sleep(1);
ret = alarm(5); //5s
printf("3st,ret = %d.\n", ret);
pause(); // 內核掛起當前進程 當前進程等待alarm信號發生被喚醒
return 0;
}
4.3、使用alarm和pause來模擬sleep
編程實例:
/*
*功能描述:使用alarm和pause來模擬sleep
*1、使用sigaction()綁定信號捕獲函數func
*2、使用alarm()函數設置一個發送信號的鬧鐘,發送的信號爲SIGALRM
*3、使用pause()掛起當前進程,當前進程等待alarm信號發生被喚醒執行func函數
*/
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
void func();
void mysleep(unsigned int seconds);
int main(void)
{
printf("before mysleep.\n");
mysleep(3);
printf("after mysleep.\n");
return 0;
}
void func(){}
void mysleep(unsigned int seconds)
{
struct sigaction act = {0};
act.sa_handler = func;
sigaction(SIGALRM, &act, NULL); //綁定信號捕獲函數func
alarm(seconds); //設置alarm函數執行seconds秒
//進程掛起,
//等待alarm函數執行完畢,產生信號SIGALRM喚醒當前進程,執行捕獲信號發生func
pause();
}
注:筆記整理記錄於——《朱老師物聯網大講堂》—3.5linux中的信號
https://edu.csdn.net/course/play/2405/37602