信号
信号是linux系统中进程间通信的一种方式, 它是一种异步的通信机制, 用来告诉某个进程, 某种事件已经发生。
系统中信号的默认行为有4种
终止
, 进程停止运行忽略
, 进程对信号不做任何回应停止
, 进程暂停运行, 并未停止, 还可以恢复继续
, 进程从停止的状态恢复运行
用户对信号可以采取自定义操作。
用户对信号可选的自定义操作有3种
捕捉
, 监测到信号时, 对信号行为重定义, 执行用户自定义的函数忽略
, 检测到信号时, 无论信号的系统默认行为是什么, 都主动忽略默认
, 检测到信号时, 执行系统默认的信号行为
自定义捕捉
信号
/**
* Description: 捕捉Ctrl + C信号
* File: signal.c |Time: 2021-05-30 17:31
*/
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
void sig_handler(int signum)
{
printf("signal [%d] catched.\n", signum);
printf("Ctrl + c pressed.\n");
// 发送终止信号终止进程
kill(getpid(), SIGKILL);
return ;
}
int main(int argc, const char *argv[])
{
// 注册一个信号处理程序, 异步信号到来时自动调用sig_handler函数
signal(SIGINT, sig_handler);
while(1)
{
sleep(1);
}
return 0;
}
自定义忽略
信号
/**
* Description: 设置信号发生时, 忽略信号的行为
* File: signal.c |Time: 2021-05-30 17:31
*/
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
int main(int argc, const char *argv[])
{
// 选择忽略信号
signal(SIGINT, SIG_IGN);
sleep(5);
kill(SIGKILL, getpid());
return 0;
}
自定义信号默认
行为
/**
* Description: 设置信号发生时采用系统默认行为
* File: signal.c |Time: 2021-05-30 17:31
*/
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
int main(int argc, const char *argv[])
{
// 选择默认的行为
signal(SIGINT, SIG_DFL);
while(1)
{
sleep(1);
}
return 0;
}
不可以自定义其行为的信号
信号常量 | 信号值 | 默认行为 | 说明 |
---|---|---|---|
SIGKILL | 9 | 终止 | 不可被忽略 |
SIGSTOP | 19 | 暂停 | 不可被忽略 |
常见的信号
信号常量 | 信号值 | 默认行为 | 说明 |
---|---|---|---|
SIGHUP | 1 | 终止 | 在用户终端关闭时产生, 通常是发给和该终端相关联的所有进程 |
SIGINT | 2 | 终止 | 在用户输入INTR字符(Ctrl + C)时产生, 内核会发送这个信号到当前终端的所有前台进程 |
SIGQUIT | 3 | 终止 | 与SIGINT类似, 但是由QUIT字符(Ctrl + )产生 |
SIGILL | 4 | 终止 | 该信号在一个进程企图执行一条非法指令时产生 |
SIGSEGV | 11 | 终止 | 该信号在非法访问内存时产生, 如野指针, 缓冲区溢出 |
SIGPIPE | 13 | 终止 | 当进程往一个没有读端的管道中写入时产生, 代表“管道破裂” |
SIGKILL | 9 | 终止 | 结束进程, 并且不能被捕捉和忽略 |
SIGCHLD | 17 | 忽略 | 子进程退出向父进程发送此信号 |
SIGSTOP | 19 | 暂停进程 | 暂停进程, 并且不能被捕捉和忽略 |
SIGTSTP | 20 | 暂停进程 | 暂停进程, 用户输入SUSP字符(Ctrl + Z)时产生 |
SIGCONT | 18 | 继续运行 | 该信号让进程进入运行态 |
SIGALRM | 14 | 终止 | 该信号用于通知进程定时器时间已到 |
SIGUSR1 | 10 | 终止 | 该信号保留给用户进程使用, 系统不会自动产生 |
SIGUSR2 | 13 | 终止 | 该信号保留给用户进程使用, 系统不会自动产生 |
信号相关的函数接口
kill
发送信号
/**
* Description: 发送一个信号
* File: signal.c |Time: 2021-05-30 17:31
*/
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
int main(int argc, const char *argv[])
{
pid_t pid = getpid();
// 3秒后发送一个信号杀掉自己
sleep(3);
kill(pid, SIGKILL);
return 0;
}
pause
阻塞等待一个信号到来
- pause会使一个进程进入无限期休眠状态, 直到一个信号来将它唤醒
- 唤醒pause的信号必须是默认终止进程类型的信号,
SIGCHLD
不好使 - pause 函数没有成功返回, 只会返回
-1
/**
* Description: pause函数接口的使用
* File: signal.c |Time: 2021-05-30 17:31
*/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>
void sig_handler(int signum){}
int main(int argc, const char *argv[])
{
int i = 0;
// 过5秒中发送时钟信号
// 修改时钟信号默认行为, 不执行任何操作
alarm(5);
signal(SIGALRM, sig_handler);
for (i = 0; i < 5; i++)
{
// pause会无限期挂起当前进程,直到有信号来唤醒
// pause只会返回-1
// 这里模拟, 当程序完成几个任务后进入无限期休眠,
// 后来时钟信号到来, 唤醒pause, 程序继续运行
if (i == 2 && -1 == pause())
{
perror("pause");
continue;
}
printf("runing something %d ... \n", i);
sleep(1);
}
return 0;
}
raise
给自己发送一个信号
/**
* Description: raise的使用
* File: signal.c |Time: 2021-05-30 17:31
*/
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
int main(int argc, const char *argv[])
{
// 5 秒后会给自己发送一个SIGKILL信号结束自己
while(1){
sleep(5);
raise(SIGKILL);
}
return 0;
}
alarm
定时给自己发送一个信号
/**
* Description: alarm的使用
* File: signal.c |Time: 2021-05-30 17:31
*/
#include <stdio.h>
#include <unistd.h>
int main(int argc, const char *argv[])
{
// 5 秒后会给自己发送一个SIGALRM信号结束自己
alarm(5);
while(1){
sleep(1);
}
return 0;
}