番禺建设局网站首页,wordpress网易云插件,wordpress调用指定文章,钟山区生态文明建设局网站信号的概念
信号是 Linux进程间通信的最古老的方式之一#xff0c;是事件发生时对进程的通知机制#xff0c;有时也称之为软件中断#xff0c;它是在软件层次上对中断机制的一种模拟#xff0c;是一种异步通信的方式。信号可以导致一个正在运行的进程被另一个正在运行的异…信号的概念
信号是 Linux进程间通信的最古老的方式之一是事件发生时对进程的通知机制有时也称之为软件中断它是在软件层次上对中断机制的一种模拟是一种异步通信的方式。信号可以导致一个正在运行的进程被另一个正在运行的异步进程中断转而处理某一个突发事件。发往进程的诸多信号通常都是源于内核。引发内核为进程产生信号的各类事件如下
----◼ 对于前台进程用户可以通过输入特殊的终端字符来给它发送信号。比如输入CtrlC 通常会给进程发送一个中断信号。
----◼ 硬件发生异常即硬件检测到一个错误条件并通知内核随即再由内核发送相应信号给相关进程。比如执行一条异常的机器语言指令诸如被 0 除或者引用了无法访问的内存区域。
----◼ 系统状态变化比如 alarm 定时器到期将引起 SIGALRM 信号进程执行的 CPU 时间超限或者该进程的某个子进程退出。
----◼ 运行 kill 命令或调用 kill 函数。
使用信号的两个主要目的是
----◼ 让进程知道已经发生了一个特定的事情。
----◼ 强迫进程执行它自己代码中的信号处理程序。
信号的特点
----◼ 简单
----◼ 不能携带大量信息
----◼ 满足某个特定条件才发送
----◼ 优先级比较高
查看系统定义的信号列表kill –l
前 31 个信号为常规信号其余为实时信号。
Linux 典型信号
编号信号名称对应事件默认动作2SIGINT当用户按下了组合键时用户终端向正在运行中的由该终端启动的程序发出此信号终止进程3SIGQUIT用户按下组合键时产生该信号用户终端向正在运行中的由该终端启动的程序发出些信号终止进程9SIGKILL无条件终止进程。该信号不能被忽略处理和阻塞终止进程可以杀死任何进程11SIGSEGV指示进程进行了无效内存访问(段错误)终止进程并产生core文件13SIGPIPEBroken pipe 向一个没有读端的管道写数据终止进程17SIGCHLD子进程结束时父进程会收到这个信号忽略这个信号18SIGCONT如果进程已停止则使其继续运行继续/忽略19SIGSTOP停止进程的执行。信号不能被忽略处理和阻塞为终止进程
信号的 5 种默认处理动作
查看信号的详细信息man 7 signal 信号的 5 种默认处理动作 ----◼ Term 终止进程
----◼ Ign 当前进程忽略掉这个信号
----◼ Core 终止进程并生成一个 Core 文件用来保存进程异常退出的错误信息
----◼ Stop 暂停当前进程
----◼ Cont 继续执行当前被暂停的进程
信号的几种状态产生、未决、递达
SIGKILL 和 SIGSTOP 信号不能被捕捉、阻塞或者忽略只能执行默认动作。
信号相关的函数
kill 函数
#include sys/types.h
#include signal.h
int kill(pid_t pid, int sig);作用给任何的进程或者进程组发送任何的信号sig
参数 ---- pid -------- 0将信号发送给指定的进程 -------- 0将信号发送给当前的进程组 -------- -1将信号发送给每一个有权限接受这个信号的进程 -------- -1这个 pid 就是某个进程组的 ID 的相反数给这个进程组发送信号 ------- sig需要发送的信号的编号或者是宏值0 表示不发送任何信号
例子
#include stdio.h
#include sys/types.h
#include signal.h
#include unistd.hint main()
{pid_t pid fork();if (pid 0) {//子进程for (int i 0; i 5; i) {printf(child \n);sleep(1);}}else if (pid 0) {//父进程printf(parent\n);sleep(2);printf(kill child\n);kill(pid, 9);}return 0;
}raise 函数
#include signal.h
int raise(int sig);作用给当前进程发送信号 参数要发送的信号 返回成功返回 0失败返回非 0 等价于kill(getpid(), sig);
abort 函数
#include stdlib.h
void abort(void);作用发送 SIGABORT 信号给当前进程杀死当前进程 等价于kill(getpid(), SIGABORT);
alarm 函数
#include unistd.h
unsigned int alarm(unsigned int seconds);作用设置定时器闹钟函数调用开始倒计时当倒计时为 0 的时候函数会给当前的进程发送一个信号SIGALRM 默认终止当前的进程每一个进程都有且只有唯一的一个定时器。
参数倒计时的时长单位是秒参数为 0 表示定时器无效不进行倒计时不发信号。可以通过传递 0 参数来取消一个定时器。
返回
---- 之前没有定时器返回 0
---- 之前有定时器返回之前的定时器倒计时剩余时间
alarm 与进程的状态运行、阻塞等无关。
首先设置一个 5 秒的定时器之后修改为 10 秒过了 10 秒时候发送 SIGALRM 信号默认关闭进程
#include unistd.h
#include stdio.hint main()
{int seconds alarm(5);printf(seconds %d\n, seconds);sleep(2);seconds alarm(10);printf(seconds %d\n, seconds);while (1) {}return 0;
}setitimer 函数
#include sys/time.h
int setitimer(int which, const struct itimerval *new_val, struct itimerval *old_value);作用设置定时器可以替代 alarm 函数。精度是微秒us。
参数
---- which定时器以什么时间定时
-------- ITIMER_REAL真实时间时间到达后发送 SIGALRM 是最常用的
-------- ITIMER_VIRTUAL用户时间时间到达后发送 SIGVTALRM
-------- ITIMER_PROF以该进程在用户态和内核态下所消耗的时间来计算时间到达后发送 SIGPROF
---- new_val设置定时器的属性
struct itimerval { //定时器结构体struct timeval it_interval; //每个阶段的时间间隔时间struct timeval it_value; //延迟多长时间执行定时器
};
struct timeval { //时间的结构体time_t tv_sec; //秒数suseconds_t tv_usec; //微秒
};---- old_value记录上一次的定时的时间参数一般不使用指定 NULL
返回成功返回 0失败返回 -1
信号捕捉函数 signal 函数
#include signal.h
sighandler_t signal(int signum, sighandler_t handler); 作用设置某个信号的捕捉行为
参数
---- signum要捕捉的信号
---- handler捕捉到信号要如何处理
-------- SIG_IGN忽略信号
-------- SIG_DFL使用信号默认的行为
-------- 回调函数函数指针类型由内核调用程序员只负责提前写好捕捉到信号后如何处理信号
返回
---- 成功返回上一次注册的信号处理函数的地址。第一次调用返回 NULL
---- 失败返回 SIG_ERR设置错误号
过3秒之后定时开始每隔2秒钟定时一次的示例
#include sys/time.h
#include stdio.h
#include stdlib.h
#include signal.hvoid myalarm(int num)
{printf(捕捉到了的信号的编号是%d\n, num);printf(xxxxxx\n);
}int main()
{//注册信号捕捉__sighandler_t ret0 signal(SIGALRM, myalarm);if (ret0 SIG_ERR) {perror(signal);exit(0);}struct itimerval new_value;//设置间隔时间new_value.it_interval.tv_sec 2;new_value.it_interval.tv_usec 0;//设置延迟时间new_value.it_value.tv_sec 3;new_value.it_value.tv_usec 0;int ret setitimer(ITIMER_REAL, new_value, NULL);printf(定时器开始了\n);if (ret -1) {perror(setitimer);exit(0);}getchar();return 0;
}程序三秒之后输出“定时器开始了”然后每隔两秒输出后面的内容
信号集
许多信号相关的系统调用都需要能表示一组不同的信号多个信号可使用一个称之为信号集的数据结构来表示其系统数据类型为 sigset_t。在 PCB 中有两个非常重要的信号集。一个称之为 “阻塞信号集” 另一个称之为“未决信号集” 。这两个信号集都是内核使用位图机制来实现的。但操作系统不允许我们直接对这两个信号集进行位操作。而需自定义另外一个集合借助信号集操作函数来对PCB 中的这两个信号集进行修改。信号的 “未决” 是一种状态指的是从信号的产生到信号被处理前的这一段时间。 信号的 “阻塞”是一个开关动作指的是阻止信号被处理但不是阻止信号产生。信号的阻塞就是让系统暂时保留信号留待以后发送。由于另外有办法让系统忽略信号所以一般情况下信号的阻塞只是暂时的只是为了防止信号打断敏感的操作。
阻塞信号集和未决信号集 用户通过键盘 Ctrl C, 产生 2 号信号 SIGINT (信号被创建) 信号产生但是没有被处理 未决 ---- 在内核中将所有的没有被处理的信号存储在一个集合中 未决信号集---- SIGINT 信号2 号信号状态被存储在第二个标志位上---- 如果这个标志位的值为 0 说明信号不是未决状态---- 如果这个标志位的值为 1 说明信号处于未决状态这个未决状态的信号需要被处理处理之前需要和另一个信号集阻塞信号集进行比较 ---- 阻塞信号集默认不阻塞任何的信号---- 如果想要阻塞某些信号需要用户调用系统的 API在处理的时候和阻塞信号集中的标志位进行查询看是不是对该信号设置阻塞了 ---- 如果没有阻塞这个信号就被处理---- 如果阻塞了这个信号就继续处于未决状态直到阻塞解除这个信号就被处理以下信号集相关的函数都是对自定义的信号集进行操作
int sigemptyset(sigset_t *set);作用清空信号集中的数据将信号集中的所有的标志位置为 0参数set值-结果参数需要操作的信号集返回成功返回 0 失败返回 -1
int sigfillset(sigset_t *set);作用将信号集中的所有的标志位置为 1参数set值-结果参数需要操作的信号集返回值成功返回0 失败返回 -1
int sigaddset(sigset_t *set, int signum);作用设置信号集中的某一个信号对应的标志位为 1表示阻塞这个信号 参数---- set值-结果参数需要操作的信号集---- signum需要设置阻塞的那个信号返回成功返回 0 失败返回 -1
int sigdelset(sigset_t *set, int signum);作用设置信号集中的某一个信号对应的标志位为 0表示不阻塞这个信号 参数---- set值-结果参数需要操作的信号集---- signum需要设置不阻塞的那个信号返回成功返回 0 失败返回 -1
int sigismember(const sigset_t *set, int signum);作用判断某个信号是否阻塞
参数
---- set需要操作的信号集---- signum需要判断的那个信号
返回
---- 1 signum被阻塞---- 0 signum不阻塞---- -1 失败 示例
#include signal.h
#include stdio.hint main()
{//创建一个信号集sigset_t set;//清空信号集的内容sigemptyset(set);//判断 SIGINT 是否在信号集 set 里int ret sigismember(set, SIGINT);if (ret 0) {printf(SIGINT不阻塞\n);}else if (ret 1) {printf(SIGINT阻塞\n);}//添加信号到信号集中sigaddset(set, SIGINT);ret sigismember(set, SIGINT);if (ret 0) {printf(SIGINT不阻塞\n);}else if (ret 1) {printf(SIGINT阻塞\n);}//从信号集中删除一个信号sigdelset(set, SIGINT);ret sigismember(set, SIGINT);if (ret 0) {printf(SIGINT不阻塞\n);}else if (ret 1) {printf(SIGINT阻塞\n);}return 0;
}sigprocmask 函数
int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);作用将自定义信号集中的数据设置到内核中设置阻塞解除阻塞替换 参数 ---- how 如何对内核阻塞信号集进行处理 -------- SIG_BLOCK:将用户设置的阻塞信号集添加到内核中内核中原来的数据不变mask | set -------- SIG_UNBLOCK:根据用户设置的数据对内核中的数据进行解除阻塞 mask ~set -------- SIG_SETMASK覆盖内核中原来的值 ---- set 已经初始化好的用户自定义的信号集 ---- oldset : 保存设置之前的内核中的阻塞信号集的状态可以是 NULL 返回成功返回 0失败返回 -1 并设置错误号 EFAULT、EINVAL
SIGKILL 和 SIGSTOP 不能被捕捉不能被忽略。
内核实现信号捕捉的过程