1.sigaction函数
- sigaction
包含头文件<signal.h>;
功能:sigaction函数用于改变进程接收特定信号后的行为;
act:信号的处理函数
old:信号安装之前,关联的行为
原型:
int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
参数:
第一个参数:
该函数的第一个参数为信号的值,可以为除SIGKILL以及SIGSTOP外的任何一个特定有效的信号(因为为这俩信号定义自己的处理函数,将
导致信号安装错误)
第二个参数:
第二个参数是指向结构sigaction的一个实例的指针,在结构sigaction的实例中,指定了对特定信号的处理,可以为空,进程会以
缺省的方式对信号进行处理
第三个参数:
oldact指向的对象用来保存原来对相应信号的处理,可指定oldact为NULL
返回值:
函数成功返回0,失败返回-1
2.sigaction结构体
- sigaction结构体
第2个参数最为重要,其中包含了对指定信号的处理、信号所传递的信息、信号处理函数执行过程中应屏蔽掉哪些函数等等
man sigaction
struct sigaction
{
//下面的2个声明(函数指针)只能任选其一
void (*sa_handler)(int);//对不可靠信号安装的原型,对可靠信号安装也可以使用该原型,只不过此时它不能传递数据
void (*sa_sigaction)(int, siginfo_t *, void *);//对可靠信号安装的原型
sigset_t sa_mask;//可以指定一个信号屏蔽字,用来屏蔽放到屏蔽字当中的信号
int sa_flags;//影响信号的行为
void (*sa_restorer)(void);//该字段可以不用关心
};
3.sigaction实例
- eg1:P20sigaction.c
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <signal.h>
#define ERR_EXIT(m) \
do \
{ \
perror(m); \
exit(EXIT_FAILURE); \
} while(0)
void handler(int sig);
int main(int argc, char *argv[])
{
struct sigaction act;
act.sa_handler = handler;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
//NULL表示不关心信号之前的行为
//sigaction关联一个动作
if (sigaction(SIGINT, &act, NULL) <0)
ERR_EXIT("sigaction error\n");
//以便有机会发送信号
for (;;)
pause();
return 0;
}
void handler(int sig)
{
printf("recv a sig = %d\n", sig);
}
- 测试:改变了信号的输出行为
- eg:P20sigaction1.c
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <signal.h>
#define ERR_EXIT(m) \
do \
{ \
perror(m); \
exit(EXIT_FAILURE); \
} while(0)
void handler(int sig);
//用sigaction模拟signal函数,类型可以从man signal中看到,所以这么写
_sighandler my_signal(int sig, _sighandler_t handler);
int main(int argc, char *argv[])
{
// struct sigaction act;
// act.sa_handler = handler;
// sigemptyset(&act.sa_mask);
// act.sa_flags = 0;
// if (sigaction(SIGINT, &act, NULL) <0)
// ERR_EXIT("sigaction error\n");
my_signal(SIGINT, handler);
for (;;)
pause();
return 0;
}
//信号原来的行为从oldact返回回来
//my_signal等价于signal函数
//signal函数既可以安装可靠信号,也可以安装不可靠信号
//但是在安装可靠信号时,函数指针只能是handler,不能用可以传递更多数据的函数
_sighandler my_signal(int sig, _sighandler_t handler)
{
strucy sigaction act;
struct sigaction oldact;
act.sa_handler = handler;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
//信号原来的行为从oldact返回回来
if (sigaction(sig, &act, &oldact) <0)
return SIG_ERR;
return oldact.handler;//返回信号原来的处理函数
}
void handler(int sig)
{
printf("recv a sig = %d\n", sig);
}
- 测试:
signal也是在可靠的机制上进行安装信号的,当信号安装完毕后,当信号处理函数被执行后,信号的默认行为是不会自动恢复的。我们可以认为他是调用sigaction来实现的。实际上,内核代码是调用do_sigaction来实现的
- eg:P20sa_mask.c
sa_mask如何改变信号的行为
在这个信号处理函数执行的时候,能否屏蔽其他信号?
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <signal.h>
#define ERR_EXIT(m) \
do \
{ \
perror(m); \
exit(EXIT_FAILURE); \
} while(0)
void handler(int sig);
int main(int argc, char *argv[])
{
struct sigaction act;
act.sa_handler = handler;
sigemptyset(&act.sa_mask);
sigaddset(&act.sa_mask, SIGQUIT);
act.sa_flags = 0;
if (sigaction(SIGINT, &act, NULL) <0)
ERR_EXIT("sigaction error\n");
for (;;)
pause();
return 0;
}
void handler(int sig)
{
printf("recv a sig = %d\n", sig);
}
-
测试:
在还没有返回的时候,出现了3号信号,程序退出,说明在2号信号处理函数执行的时候,没有屏蔽3号信号,直接被递达了
按下ctrl \并没有马上退出来,因为该信号在先前信号还没有运行完的时候阻塞了,直到先前信号运行完毕,该信号才能递达
-
eg:P20sa_,ask1.c
注意区别:sa_mask中的掩码能阻塞信号,当处理函数在执行的过程中,加入到掩码中的信号将要被阻塞,直到handler返回才能被递达;
sigpromask表示将这些集合中的信号添加到进程的信号屏蔽字当中,这些信号就不能被递达了,即使发生了
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <signal.h>
#define ERR_EXIT(m) \
do \
{ \
perror(m); \
exit(EXIT_FAILURE); \
} while(0)
void handler(int sig);
int main(int argc, char *argv[])
{
//当处理函数在执行的过程中,加入到掩码中的信号将要被阻塞
struct sigaction act;
act.sa_handler = handler;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
//将SIGINT加入到了进程中的信号屏蔽字,将对应的位置为1
//SIGINT信号发生的时候,不能被递达,会处于pending未决状态
sigset_t s;
sigemptyset(&s);
sigaddset(&s, SIGINT);
sigprocmask(SIG_BLOCK, &s, NULL);
if (sigaction(SIGINT, &act, NULL) <0)
ERR_EXIT("sigaction error\n");
for (;;)
pause();
return 0;
}
void handler(int sig)
{
printf("recv a sig = %d\n", sig);
}
-
测试:
按下ctrl \就可以退出程序,因为他没有阻塞,所以他被递达了 -
Makefile
.PHONY:clean all
CC=gcc
CFLAGS=-Wall -g
BIN=01sigac
all:$(BIN)
%.o:%.c
$(CC) $(CFLAGS) -c $< -o $@
clean:
rm -f *.o $(BIN)