二、函数sigaction
修改信号处理动作(通常在Linux用来注册一个信号的捕捉函数)
#inlcude<signal.h>
int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
参数:
- act:传入参数,新的处理方式
- oldact:传出参数,旧的处理方式
struct sigaction
{
void (*sa_handler)(int);
void (*sa_sigaction)(int, siginfo_t*, void*);
sigset_t sa_mask;
int sa_flags;
void (*sa_restorer)(void);
};
分析:
- sa_restorer:该元素是过时的,不应该使用, POSIX.1标准将不指定该元素。(弃用)
- sa_sigaction:当sa_flags被指定为SA_SIGINFO标志时,使用该信号处理程序(很少使用)
- sa_handler:指定信号捕捉后的处理函数名(即注册函数)。可赋值为SIG_IGN表忽略或SIG_DFL表执行默认动作
- sa_mask:调用信号处理函数时,所要屏蔽的信号集合(信号屏蔽字)。注意仅在处理函数调用期间屏蔽。(默认属性:信号捕捉函数执行期间,自动屏蔽本信号)
- sa_flag:通常设置为0,表默认属性
1. 测试代码:
#include<stdio.h>
#include<signal.h>
#include<stdlib.h>
#include<unistd.h>
void docatch(int signo)
{
printf("%d signal is catch\n", signo);
}
int main()
{
int ret;
struct sigaction act;
act.sa_handler = docatch;
sigemptyset(&act.sa_mask);
sigaddset(&act.sa_mask, SIGQUIT);
act.sa_flags = 0; //默认属性:信号捕捉函数执行期间,自动屏蔽本信号
ret = sigaction(SIGINT, &act, NULL);
if(ret < 0) {
perror("sigaction error");
exit(1);
}
while(1)
sleep(1);
return 0;
}
输出结果:
信号捕捉特性:
- 进程正常运行时,默认PCB有一个信号屏蔽字,假定为☆,它决定了进程自动屏蔽哪些信号,当注册了某个信号步捕捉函数,捕捉到该信号以后,要调用该函数,而该函数有可能执行很长时间,在这期间所屏蔽的信号不由☆指定,而由sa_mask来指定,调用完信号处理函数,再恢复为☆。
- xxx信号捕捉函数执行期间,XXX信号自动屏蔽。
- 阻塞的常规信号不支持排队,产生多次只记录一次(后32个实时信号支持排队)
2. 测试代码:
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
void docatch(int signo)
{
printf("%d signal is catch\n", signo);
sleep(10);
printf("--------------finish\n");
}
int main()
{
int ret;
struct sigaction act;
act.sa_handler = docatch;
sigemptyset(&act.sa_mask);
sigaddset(&act.sa_mask, SIGQUIT);
act.sa_flags = 0;
ret = sigaction(SIGINT, &act, NULL);
if (ret < 0)
{
perror("sigaction error");
exit(1);
}
while (1) sleep(1);
return 0;
}
输出结果:
#include <sys/wait.h>
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
void sys_err(char *str)
{
perror(str);
exit(1);
}
void do_sig_child(int signo)
{
int status;
pid_t pid;
while ((pid = waitpid(0, &status, WNOHANG)) > 0)
{
if (WIFEXITED(status))
printf("---------------------------child %d exit %d\n", pid, WEXITSTATUS(status));
else if (WIFSIGNALED(status))
printf("child %d cancel signal %d\n", pid, WTERMSIG(status));
}
}
int main()
{
pid_t pid;
int i;
for (i = 0; i < 10; i++)
{
if ((pid = fork()) == 0)
break;
else if (pid < 0)
sys_err("fork");
}
if (pid == 0) //子进程
{
int n = 1;
while (n--)
{
printf("child ID %d\n", getpid());
sleep(1);
}
return i + 1;
}
else if (pid > 0) //父进程
{
struct sigaction act; //SIGCHLD阻塞
act.sa_handler = do_sig_child;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
sigaction(SIGCHLD, &act, NULL); //解除对SIGCHLD的阻塞
while (1)
{
printf("parent ID %d\n", getpid());
sleep(1);
}
}
return 0;
}