sigaction函數
sigaction函數的功能是用於改變進程接收到特定信號后的行為。
int sigaction(int signum, const struct sigaction *act,struct sigaction *oldact);
參數
--第一個參數是信號的值,可以為除了SIGKILL及SIGSTOP外的任何一個特定有效的信號(因為這兩個信號定義了自己的處理函數,將導致信號安裝錯誤)
--第二個參數是指向節后sigaction的一個實例的指針,在sigaction的實例中,指定了對特定信號的處理,可以為NULL,進程會以缺省方式對信號處理
--第三個參數oldact指向的對象用來保存原來對相應信號的處理,可以為NULL
返回值:函數成功返回0,失敗返回-1。
sigaction函數檢查或修改與指定信號相關聯的處理動作,該函數取代了signal函數。
因為signal函數在信號未決時接收信號可能出現問題,所以使用sigaction更安全。
sigaction結構體
struct sigaction {
void (*sa_handler)(int);//信號處理程序 不接受額外數據
void (*sa_sigaction)(int, siginfo_t *, void *);//信號處理程序,能接受額外數據,可以和sigqueue配合使用
sigset_t sa_mask;
int sa_flags;//影響信號的行為SA_SIGINFO表示能接受數據
void (*sa_restorer)(void);//廢棄
};
--第二個參數最為重要,其中包含了對指定信號的處理、信號所傳遞的信息、信號處理函數執行過程中贏屏蔽掉哪些函數等等。
--回調函數sa_handler、sa_sigaction只能任選其一
//捕捉信號
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <signal.h>
void catch_signal(int sign)
{
switch(sign)
{
case SIGINT:
//SIGINT默認行為是退出進程
printf("SIGINT signal\n");
exit(0);
break;
case SIGALRM:
//SIGALRM默認行為是退出進程
printf("SIGALRM signal\n");
break;
case SIGKILL:
printf("SIGKILL signal\n");
break;
}
}
//建議使用封裝之后的mysignal
int mysignal(int sign,void (*func)(int))
{
struct sigaction act,oact;
//傳入回調函數
act.sa_handler=func;
//將act的屬性sa_mask設置一個初始值
sigemptyset(&act.sa_mask);
act.sa_flags=0;
return sigaction(sign,&act,&oact);
}
int main(int arg, char *args[])
{
mysignal(SIGINT,catch_signal);
mysignal(SIGALRM,catch_signal);
mysignal(SIGKILL,catch_signal);
int i=0;
while(1)
{
printf("hello god %d\n",i++);
sleep(1);
}
return 0;
}
sigqueue函數
--新的發送信號系統調用,主要是針對實時信號提出的支持信號帶有參數,與sigaction()函數配合使用
--注意:和kill函數相比int kill(pid_t pid,int signo)多了參數
--原型 int sigqueue(pid_t pid,int signo,const union sigval value);
--參數 sigqueue的第一個參數是指定接收信號的進程pid,第二個參數確定即將發送的信號,
第三個參數是一個聯合數據結構union sigval,指定了信號傳遞的參數,即通常所說的4字節值。
--函數成功返回0,失敗返回-1,並且更新errno
--sigqueue()比kill()傳遞了更多的附加信息,但sigqueue()只能向一個進程發送信號,而不能發送信號給一個進程組
--union sigval聯合體
typedef union sigval
{
int sival_int;
void * sival_ptr;
}sigval_t;
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
/*
siginfo_t {
int si_signo; // Signal number
int si_errno; // An errno value
int si_code; // Signal code
int si_trapno; // Trap number that caused
hardware-generated signal
(unused on most architectures)
pid_t si_pid; // Sending process ID
uid_t si_uid; // Real user ID of sending process
int si_status; // Exit value or signal
clock_t si_utime; // User time consumed
clock_t si_stime; // System time consumed
sigval_t si_value; // Signal value
int si_int; // POSIX.1b signal
void *si_ptr; // POSIX.1b signal
int si_overrun; // Timer overrun count; POSIX.1b timers
int si_timerid; // Timer ID; POSIX.1b timers
void *si_addr; // Memory location which caused fault
int si_band; // Band event
int si_fd; // File descriptor
}
*/
void catch_signal(int signo,siginfo_t *resdata,void *unkonwp)
{
printf("signo=%d\n",signo);
printf("return data :%d\n",resdata->si_value.sival_int);
printf("second return data:%d\n",resdata->si_int);
return ;
}
int main(int arg, char *args[])
{
pid_t pid=0;
pid=fork();
if(pid==-1)
{
printf("fork() failed! error message:%s\n",strerror(errno));
return -1;
}
if(pid==0)
{
printf("i am child!\n");
//等待父進程執行完信號安裝
sleep(5);
//向父進程發送帶數據的信號
union sigval sigvalue;
sigvalue.sival_int=222;
//發送信號
if(sigqueue(getppid(),SIGINT,sigvalue)==-1)
{
printf("sigqueue() failed ! error message:%s\n",strerror(errno));
exit(0);
}
printf("子進程信號發送成功!\n");
exit(0);
}
if(pid>0)
{
printf("i am father!\n");
//安裝信號
struct sigaction act;
//初始化sa_mask
sigemptyset(&act.sa_mask);
act.sa_sigaction=catch_signal;
//一旦使用了sa_sigaction屬性,那么必須設置sa_flags屬性的值為SA_SIGINFO
act.sa_flags=SA_SIGINFO;
//安裝信號
if(sigaction(SIGINT,&act,NULL)!=0)
{
printf("sigaction() failed! \n");
return -1;
}
//等待子進程返回
int status=0;
wait(&status);
printf("game over!\n");
}
return 0;
}
