sigaction():信号处理函数 可以携带信息~
头文件 #include
int sigaction(int signum,const struct sigaction *act, struct sigaction *oldact));
一个参数为信号的值,可以为除SIGKILL及SIGSTOP外的任何一个特定有效的信号(为这两个信号定义自己的处理函数,将导致信号安装错误)。
第二个参数是指向结构sigaction的一个实例的指针,在结构sigaction的实例中,指定了对特定信号的处理,可以为空,进程会以缺省方式对信号处理;
第三个参数oldact指向的对象用来保存原来对相应信号的处理,可指定oldact为NULL。
如果把第二、第三个参数都设为NULL,那么该函数可用于检查信号的有效性。
struct sigaction
{
union
{
__sighandler_t _sa_handler;
void (*_sa_sigaction)(int, struct siginfo *, void *);
} _u
sigset_t sa_mask;
unsigned long sa_flags;
void (*sa_restorer)(void);
}
1、联合数据结构中union的两个元素_sa_handler以及*_sa_sigaction指定信号关联函数,
由_sa_handler指定的处理函数只有一个参数,即信号值,所以信号不能传递除信号值之外的任何信息;
由_sa_sigaction是指定的信号处理函数带有三个参数,是为实时信号而设的(当然同样支持非实时信号),它指定一个3参数信号处理函数。第一个参数为信号值,第三个参数没有使用(posix没有规范使用该参数的标准),第二个参数是指向siginfo_t结构的指针,结构中包含信号携带的数据值
typedef struct
{
int si_signo; /*信号值,对所有信号有意义*/
int si_errno; /*errno值,对所有信号有意义*/
int si_code; /*信号产生的原因,对所有信号有意义*/
union
{
sigval si_value;
}
}siginfo_t;
//结构的第四个域同样为一个联合数据结构:
union sigval
{
int si_int;
void *si_ptr;
}
深深的不能理解为什么结构体中的第四个变量又多次一举声明为sigval?
像下面这样不是更好?是不是因为处理的信号不同,结构体里的值也会发生变化?
// 自己理解
typedef struct
{
int si_signo; /*信号值,对所有信号有意义*/
int si_errno; /*errno值,对所有信号有意义*/
int si_code; /*信号产生的原因,对所有信号有意义*/
union
{
int si_int;
void *si_ptr;
}
}siginfo_t;//
接受信号例子:
#include
#include
#include
#include
#include
void new_op(int,siginfo_t*, void*);
int main(int argc,char **argv)
{
struct sigaction act;// 创建sigaction结构体
int sig;
pid_t pid;
pid=getpid();
printf("PID is %d\n", (int)pid);
sig=atoi(argv[1]); //输入时第一个参数 信号的值 (kill -l) 可以查看所有信号
sigemptyset(&act.sa_mask);
act.sa_sigaction=new_op;//处理函数
act.sa_flags=SA_SIGINFO;//标志
if(sigaction(sig,&act,NULL)<0)
{
printf("install sigal error\n");
exit(0);
}
while(1)
{
sleep(2);
printf("wait for the signal\n");
}
}
void new_op(int signum,siginfo_t *info,void *myact)
{
printf("the int value is %d \n",info->si_int);
}
sa_sigaction函数指针指向了处理函数new_op,在接收到规定信号,执行相应的new_op 操作,并将获得的值(info->si_int)显示出来
也就是说在编程中,对于sigaction()特定信号的处理,只需要将指针指向sa_sigaction 指向处理函数就行,剩下数据的接受可在处理函数参数 siginfo_t 中直接操作
此时的new_op 更像一个中断函数
@ubuntu:~/Desktop$ ./sig1 50 //输入参数
PID is 3344 // 结果显示
wait for the signal
wait for the signal
wait for the signal
wait for the signal
the int value is 8
wait for the signal
wait for the signal
wait for the signal
///
发送信号例子:
系统调用sigqueue发送信号时,sigqueue的第三个参数就是sigval联合数据结构,当调用sigqueue时,该数据结构中的数据就将拷贝到信号处理函数的第二个参数中。
#include
#include
#include
#include
#include
#include
// sigqueue 发送信号信息,带sival_int的信息
main(int argc,char **argv)
{
pid_t pid;
int signum;
union sigval mysigval;
signum=atoi(argv[1]); //要发送信号的信号值
pid=(pid_t)atoi(argv[2]);//发送进程的pid
mysigval.sival_int=8;//不代表具体含义,只用于说明问题
if(sigqueue(pid, signum, mysigval)==-1)
{
printf("send error\n");
exit(0);
}
sleep(2);
}
@ubuntu:~/Desktop$ ./sig2 50 3344 //
输入参数
程序运行次序 先运行sig1 使其不断的等待接收 再运行sig2 并在后面加入信号值为50 进程号(pid)为3344参数
结果解释:当sig1 不断等待时,如果sig2发送的信号到达,就显示the int value is 8 表示已经接收到信号
二。 signal()
#include
void (*signal( int signum, void(*handler) (int) ))(int);
第一个参数指定信号的值,第二个参数指定针对前面信号值的处理
如果signal()调用成功,返回最后一次为安装信号signum而调用signal()时的handler值;失败则返回SIG_ERR。
Linux中signal 和signalaction 的区别就在是否能携带信号信息,在Uinx中貌似还有区别
三.实时信号 非实时信号
// 这个例子主要是对于实时信号和非实时信号阻塞的验证
// 利用另一个终端连续发送 kill -SIGRTMIN 进程号 可验证实时信号是可靠的,不会丢失
// 利用在本终端连续发送ctrl+c可发现最终是受到一个信号! 即信号不可靠
//方法:先将两个信号屏蔽,并sleep一会儿 ,这期间连续发送信号~
#include
#include
#include
#include
void sig_handler(int,siginfo_t*,void*);
int main(int argc,char**argv)
{
struct sigaction act;
sigset_t newmask, oldmask;
int rc;
sigemptyset(&newmask);
sigaddset(&newmask, SIGINT); //非实时信号
sigaddset(&newmask, SIGRTMIN); //实时信号
sigprocmask(SIG_BLOCK, &newmask, &oldmask); //屏蔽信号,使其不会立即执行信号的动作
act.sa_sigaction = sig_handler;
act.sa_flags = SA_SIGINFO;
if(sigaction(SIGINT, &act, NULL) < 0)
{
printf("install sigal error\n");
}
if(sigaction(SIGRTMIN, &act, NULL) < 0)
{
printf("install sigal error\n");
}
printf("pid = %d\n", getpid());
sleep(20); // 休眠中 ,发送过来的信号会排队
sigprocmask(SIG_SETMASK, &oldmask, NULL); //打开屏蔽,信号执行相应的操作
return 0;
}
void sig_handler(int signum,siginfo_t *info,void *myact)
{
if(signum == SIGINT)
printf("Got a common signal\n");
else
printf("Got a real time signal\n");
}
非实时信号都不支持排队,都是不可靠信号;实时信号都支持排队,都是可靠信号。
四。信号集合
信号集的数据类型
typedef struct {
unsigned long sig[_NSIG_WORDS];
} sigset_t
信号集用来描述信号的集合,linux所支持的所有信号可以全部或部分的出现在信号集中,主要与信号阻塞相关函数配合使用。下面是为信号集操作定义的相关函数:
#include
int sigemptyset(sigset_t *set);
int sigfillset(sigset_t *set);
int sigaddset(sigset_t *set, int signum)
int sigdelset(sigset_t *set, int signum);
int sigismember(const sigset_t *set, int signum);
sigemptyset(sigset_t *set)初始化由set指定的信号集,信号集里面的所有信号被清空;
sigfillset(sigset_t *set)调用该函数后,set指向的信号集中将包含linux支持的64种信号;
sigaddset(sigset_t *set, int signum)在set指向的信号集中加入signum信号;
sigdelset(sigset_t *set, int signum)在set指向的信号集中删除signum信号;
sigismember(const sigset_t *set, int signum)判定信号signum是否在set指向的信号集中。