信號原理
- 信號機制:事件促使內(nèi)核向進程發(fā)送信號
- 事件類型:
- 鍵盤按鍵請求內(nèi)核產(chǎn)生信號:ctrl+c锻狗、ctrl+/等
- 進程執(zhí)行出錯時掌腰,如越界訪問狰住,0做除數(shù),整形溢出齿梁。內(nèi)核給進程發(fā)信號
- 一個進程調(diào)用kill給另一個進程發(fā)信號催植。
- 信號機制過程
信號未決(信號處理之前的狀態(tài)):事件產(chǎn)生->內(nèi)核發(fā)送信號給指定進程->信號注冊(信號進PCB)
信號遞送(信號處理動作):信號被屏蔽/若未被屏蔽肮蛹,信號從PCB注銷->信號處理 - 信號處理方式
- 按默認方式處理:man 7 signal可以查看每個信號的默認處理方式
- 忽略信號,SIGKILL和SIGSTOP不能被忽略
- 捕捉信號创南,作出反應(yīng)
- 可用于進程間使用信號通信
- 異步通信機制(約定信號處理機制)
-
shell中用 kill -l 查看信號
- 信號分類
- 小于32號為不可靠信號伦忠,不支持信號隊列。后面為可靠信號稿辙,支持信號隊列
- 同步信號:本進程操作產(chǎn)生的信號昆码。異步信號:進程之外的事件引發(fā)的信號。
- 信號的意義見官方信號表
http://man7.org/linux/man-pages/man7/signal.7.html
也可在終端輸入man 7 signal
查看信號詳細信息和默認處理方式
信號處理函數(shù)API
include <signal.h>
__sighandler_t signal(int signum,__sighandler_t handler)
參數(shù)表:
signum:要處理的信號
handler:信號處理函數(shù)
- __sighandler_t的定義:typedef void (*__sighandler_t)(int);
函數(shù)指針:返回值為void邻储,有一個類型為int的參數(shù)
此參數(shù)對應(yīng)三種不同的應(yīng)對- SIG_IGN:忽略
- SIG_DFL:默認
- 函數(shù)名:用戶自己定義的反應(yīng)函數(shù)
返回值:
不為-1:成功
SIG_ERR:出錯
示例代碼:
#include <signal.h>
#include <stdlib.h>//perror,exit()
#include <unistd.h>//fork(),pause()
#include <sys/wait.h>//wait()
#include <iostream>
using namespace std;
void fun(int signal)
{
cout << "process:"<<getpid()<<"have captured the signal " << endl;
}
int main()
{
int pid;
if( ( pid = fork() ) == -1 )
{
perror("fork");
exit(1);
}
else if(pid == 0)//son process
{
signal(SIGINT,fun);
//SIGINT:signal from keyboard
//約定信號處理函數(shù)
cout << "waiting for signal" << endl;
pause();//掛起等待信號
}
else//parent process
{
sleep(1);
kill(pid,SIGINT);//發(fā)送信號
wait(NULL);
}
}
也可發(fā)送信號10(用戶自定義信號)來進行進程通信
signal函數(shù)存在的問題
- 信號處理不可靠
處理結(jié)束后需要再次設(shè)置監(jiān)聽赋咽,所以常用此結(jié)構(gòu)
這種結(jié)構(gòu)在相應(yīng)處理完信號到重設(shè)監(jiān)聽狀態(tài)有一段危險時間(雖然很短)void handler(int signo) { signal(SIGINT,handler); ... }
- 不方便獲取當(dāng)前信號處理方式
- 無法處理多個信號--無法阻塞信號
其他信號相關(guān)api(待更新)
- sigaction:
int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
- 當(dāng)act為空,oldact非空:獲取signum當(dāng)前的處理方式
- 當(dāng)act非空吨娜,oldact為空:安裝信號處理函數(shù)
- sigaction結(jié)構(gòu)體
struct sigaction {
void (*sa_handler)(int);//信號處理函數(shù)句柄脓匿,不帶參數(shù)
void (*sa_sigaction)(int, siginfo_t *, void *);//信號處理函數(shù)句柄,帶參數(shù)
sigset_t sa_mask;//響應(yīng)信號:哪些信號可以阻塞等待執(zhí)行
int sa_flags;//設(shè)置是否在信號響應(yīng)后恢復(fù)對信號的默認處理
void (*sa_restorer)(void);
}
一個小例子
通過argv來傳送pid和signum
發(fā)送端
#include <signal.h>
#include <sys/time.h>
#include <unistd.h>
#include <sys/types.h>
#include <stdlib.h>
#include <stdio.h>
void main(int argc,char**argv)
{
pid_t pid;
pid=(pid_t)atoi(argv[1]);
int signum;
signum = atoi(argv[2]);
union sigval mysigval;
if(kill(pid,signum)==-1)
printf("send error\n");
sleep(2);
}
接收端
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>//atoi
void new_op(int signum)
{
printf("recieve signumm %d\n",signum);
}
int main(int argc,char**argv)
{
struct sigaction act;
sigemptyset(&act.sa_mask);
act.sa_handler=new_op;
act.sa_flags=SA_RESETHAND;
if(sigaction(30,&act,NULL)<0)
{
printf("install sigal error\n");
}
pid_t pid;
pid=getpid();
printf("pid : %d\n",pid);
sleep(10);
}
- kill:發(fā)送信號
- raise:給自己發(fā)信號
- alarm:計時器
- pause:掛起(等信號)(pause+alarm = sleep):
- sigqueue:可以在發(fā)信號的時候傳參