信号的理解

进程信号:是一种软件中断,一种事件通知机制。通知进程发生了某个事件,打断进程当前操作,去处理这个事件。
种类:使用kill -l指令进行查看;62种信号
信号的生命周期:产生,注册,注销,处理。在生命周期外还会有阻塞
信号的产生:
(1)硬件产生:

		ctrl+c:会使当前终端前台进程退出(SIGINT)   
		ctrl+\:  (SIGQUIT)
		ctrl+z : 把当前进程转到后台运行,使用’ fg ‘命令恢复。比如top -d1 然后ctrl+z ,到后台,然后fg,重新恢复	

(2)系统调用

			kill命令:杀死一个进程-给进程发送一个信号-默认是终止信号
			kill -signum pid   
			int kill(pid_t pid, int sig)
			pid:指定要将信号发送给哪个进程;
			sig:指定要发送的信号
			返回值:成功返回0;失败返回-1;				
			int raise(int sig);给调用进程自身发送指定信号
			void abort(void):给进程发送一个SIGABRT信号

(3)软件产生

unsigned int alarm(unsigned int seconds);设置一个计时器
调用alarm函数设定一个闹钟,也就是告诉内核在seconds秒之后给当前进程发送				  				
SIGALRM信号,该信号的默认动作是终止当前进程

下面这个程序的作用是一秒之内count不停的加加,1秒钟到了就被SIGALRM信号终止。

1 #include<iostream>                                                                                                                                                     
    2 #include<signal.h>
    3 #include<unistd.h>
    4 using namespace std;
    5 void handler(int signo)
    6 {
    7     cout<<"catch a signal"<<signo<<endl;
    8 }
    9 int main(int argc,char *argv[])
   10 {
   11     alarm(1);
   12     int count = 0;
   13     while(1)
   14     {
   15         cout<<count++<<endl;
   16     }
   34     return 0;
   35 }

(4)硬件产生

	硬件异常被硬件以某种方式被硬件检测(例如MMU/寄存器/运算器)到并通知内核,然后内核向当前进程发送适当的信号。
例如1/0 时CPU的运算单元会产生异常,内核将这个异常解释为SIGFPE信号
(浮点型错误)发送给进程。再比如当前进程非法访问了内存地址,MMU会产				
	生异常,内核将这个异常解释为SIGSEGV信号(段错误)发送给进程。

信号在进程中注册

在未决信号集合(pending位图)中标记信号+添加信号的信息节点
在pcb中有个未决信号集合—还没有被处理的信号的集合—位图
可靠信号的注册:不管信号是否已经被注册过,都会注册一次,添加一个信号节点。
非可靠信号的注册:如果信号已经被注册并且还未被处理,则什么都不做,否则将注册。

在这里插入图片描述
信号的注销:在pcb中删除信号信息节点,重置位图

非可靠信号:删除信息节点,直接位图重置
可靠信号:删除信息节点之后,确定没有相同节点才会重置位图

信号的处理:信号的递达—执行信号的处理回调函数
方式:默认,忽略,自定义捕捉

在这里插入图片描述

   头文件:#include <signal.h>
   typedef void (*sighandler_t)(int);
   sighandler_t signal(int signum, sighandler_t handler);
   signum:信号值; handler:信号要新指定的处理方式
handler:SIG_DFL-默认;SIG_IGN-忽略;自定义—typedef void(*sighandler_t)(int)
返回值:成功返回信号原来的处理方式;失败返回-1-SIG_ERR

在这里插入图片描述

信号的阻塞:
阻塞一个信号表示收到这个信号之后暂时不去处理,直到进程解除阻塞之后进行处理。
在pcb中有一个信号阻塞集合,在这个集合中标记哪个信号则表示阻塞哪个信号

block位图:用来记录信号是否被屏蔽或被阻塞
pending位图:记录进程是否收到特定信号。
handler:记录信号的处理方式

在这里插入图片描述

在这里插入图片描述

		int sigprocmask(int how, sigset_t *set, sigset_t *oldset)
			how:要对信号阻塞集合进行的操作类型
			SIG_BLOCK:将set集合中的信号添加到阻塞集合中
			SIG_UNBLOCK:从阻塞集合中移除set集合中的信号
			SIG_SRTMASK:将set集合中的信号设置为阻塞集合的信号
			oldset:用于保存修改前,阻塞集合中的信息,不需要保存时则置空
		返回值:成功返回0;失败返回-1;
		自定义修改两种信号(可靠,非可靠)signal
		先阻塞一波信号 sigprocmask SIG_BLOCK
		让程序运行暂停 getchar,暂停期间给程发送信号,让程序运行继续
		解除信号阻塞	sigprocmask SIG_UNBLOCK
		int sigemptyset(sigset_t *set); 清空set集合
		int sigfillset(sigset_t *set);  将所有信号添加到set集合中
		int sigaddset(sigset_t *set, int signum);将指定信号添加到集合中
		int sigdelset(sigset_t *set, int signum);从集合中移除指定信号
		int sigismember(const sigset_t *set,int signum) ;判断信号是否在set集合中

信号的捕捉:
在这里插入图片描述
递达的条件:信号是从内核态切换到用户态的时候进行相关检测(同时检测是否有新线程到来,是否进行进程切换)
陷入内核:用户态到内核态。
返回到用户:内核到用户态。

sigaction函数:
头文件:#include <signal.h>
int sigaction(int signum,const struct sigaction *act,struct sigaction *oldact)

在这里插入图片描述
具体使用方法如下:

  #include<iostream>
  #include<signal.h>
  #include<unistd.h>
  using namespace std;
  void sigcb(int signo)
  {
      cout<<"signo:"<<signo<<endl;                                                
  }
  int main()
  {
      struct sigaction act,oact;
      act.sa_handler = sigcb;
      act.sa_flags = 0;
      sigemptyset(&act.sa_mask);//处理一个信号时所要屏蔽的其他信号,不关心则清空。
      sigaction(2,&act,&oact);
      while(1);
      sleep(5);
      return 0;
  }

测试结果如下:
在这里插入图片描述

2号信号被sigaction函数(系统调用)自定义为打印该信号的signo;

volatile关键字

作用:保存内存的可见性,被该关键字修饰的变量不允许被系统优化。
对该变量的任何操作,必须在真实的内存中进行操作,凡是被volatile修饰的
变量是不可覆盖的,在任何执行流当中,读取该数据时,必须从该数据真实
存储的位置进行读取,不能读取中间的临时缓存数据。

SIGCHILD:

	父进程等待子进程的方式有三种:
		1.wait(NULL);
		2.waitpid(-1,&status,WNOHANG);
		3.父进程可以自 定义SIGCHLD信号的处理函数,在信号处理函数中
		调用wait清理子进程即可。
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
void handler(int sig)
{
 pid_t id;
 while( (id = waitpid(-1, NULL, WNOHANG)) > 0){
 printf("wait child success: %d\n", id);
 }
 printf("child is quit! %d\n", getpid());
}
int main()
{
 signal(SIGCHLD, handler);
 pid_t cid;
 if((cid = fork()) == 0){//child
 printf("child : %d\n", getpid());
 sleep(3);
 exit(1);
 }
 while(1){
 printf("father proc is doing some thing!\n");
 sleep(1);
 }
 return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

倚心

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值