信号是系统响应某个条件而产生的事件,进程接收到信号号会执行相应的操作;
与信号有关的系统调用在<signal.h>头文件中。
1、信号的存储位置
vim /usr/include/x86_64-linux-gnu/bits/signum.h
2、常见信号的值,即对应的功能说明
信号名称 | 说明 |
---|---|
SIGABORT | *进程异常终止 |
SIGALRM |
超时警告 |
SIGFPE | *浮点运算符异常 |
SIGHUP | 连接挂断 |
SIGILL | *非法指令 |
SIGINT | 终端中断 |
SIGKILL | 终止进程(此信号不能被捕获或忽略) |
SIGPIPE | 向无读进程的管道写数据 |
SIGQUIT | 终端退出 |
SIGSEGV | *无效内存段访问 |
SIGTERM | 终止 |
SIGUSR1 | 用户定义信号1 |
SIGUSR2 | 用户定义信号2 |
3、信号的值在系统源码中的定义
#define 信号名称 信号代号
#define SIGHUP 1
#define SIGINT 2 //键盘按下 Ctrl+c 时,会产生终端中断信号
#define SIGQUIT 3//键盘按下 Ctrl+\ 时,会产生终端退出信号
#define SIGILL 4
#define SIGTRAP 5
#define SIGABRT 6
#define SIGIOT 6
#define SIGBUS 7
#define SIGFPE 8
#define SIGKILL 9 //该信号的响应方式不允许改变
#define SIGUSR1 10
#define SIGSEGV 11
#define SIGUSR2 12
#define SIGPIPE 13 //读端关闭的描述符,写端写入时产生,该信号会终止程序(向
无读进程的管道写数据)
#define SIGALRM 14
#define SIGTERM 15 //系统 kill 命令默认发送的信号
#define SIGSTKFLT 16
#define SIGCHLD 17 //子进程结束后,会默认给父进程发送该信号
#define SIGCONT 18
#define SIGSTOP 19
#define SIGTSTP 20
#define SIGTTIN 21
#define SIGTTOU 22
#define SIGURG 23
4、响应方式
三种响应方式:默认,忽略,自定义。
设置信号的响应方式:通过函数signal()
man signal:
默认:SIG_DFL;
忽略:SIG_IGN;
自定义:void fun_sig(int sig);
(1)默认响应方式
正常是默认,代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>
int main()
{
while(1)
{
printf("main run\n");
sleep(1);
}
exit(0);
}
(2)自定义响应方式
通过signal系统调用更改信号的响应方式:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>
#include <signal.h>
void sig_fun(int sig)
{
printf("sig=%d\n",sig);
}
int main()
{
signal(SIGINT,sig_fun);//回调函数
while(1)
{
printf("main run\n");
sleep(1);
}
exit(0);
}
(3)忽略
SIG_IGN
signal(SIGINT,SIG_IGN);
(4)扩展练习
收到SIGINT信号,第一次打印信号的代号,第二次按照默认方式把进程结束;
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>
#include <signal.h>
void sig_fun(int sig)
{
printf("sig=%d\n",sig);
signal(sig,SIG_DFL);
}
int main()
{
signal(SIGINT,sig_fun);
//signal(SIGINT,SIG_IGN);
while(1)
{
printf("main run\n");
sleep(1);
}
exit(0);
}
(5)实现kill命令
man 2 kill:系统调用
向pid进程发送sig信号;返回值-1表示失败,0表示成功
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<signal.h>
#include<unistd.h>
#include <errno.h>
int main(int argc,char *argv[])
{
if(argc!=3)
{
printf("argc error\n");
return -1;
}
int pid=0;
int sig=0;
sscanf(argv[1],"%d",&pid);
sscanf(argv[2],"%d",&sig);
if(kill(pid,sig)==-1)
{
perror("kill error\n");
}
exit(0);
}
5、SIGCHLD信号
子进程结束,父进程会收到内核发送的SIGCHLD信号;;
(1)验证信号
改变SIGCHLD信号的响应方式
(2)处理僵死进程(wait结合信号)
include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<signal.h>
#include<sys/wait.h>
void fun(int sig)
{
printf("sig=%d\n",sig);
int val=0;
int id=wait(&val);
}
int main()
{
int n=0;
char *s=NULL;
pid_t pid=fork();
if(pid==-1)
{
printf("fork error\n");
exit(1);
}
if(pid ==0)
{
n=3;
s="child";
}
else
{
signal(SIGCHLD,fun);
n=7;
s="parent";
}
for(int i=0;i<n;i++)
{
printf("s=%s\n",s);
sleep(1);
}
exit(0);
}