Linux--进程信号

目录

一,信号是什么

1,信号产生前

2,信号产生中

3,信号处理

1,默认行为

2,自定义行为

3,忽略信号

二,信号如何发送和怎么记录

1,信号如何发送

2,信号的记录

三,信号在内核中如何表示的

四,信号的捕捉

1,内核如何实现信号捕捉

2,为什么需要状态切换 

3,sigaction

​五,可重入函数

六,volatile关键字

一,信号是什么

1,信号产生前

在信号产生前,我们已经知道了信号产生的意义,并且知道信号产生后需要做什么,为什么能识别呢,因为已经知道了信号特征和怎么识别以及对应的处理过程(已经被提前培养好怎么处理信号)

2,信号产生中

        当信号发生后,可能我们正在做优先级更高的事情,比如正在打游戏,快递来了,可能先打完游戏,再去楼下拿快递,所以信号产生后,我们会在合适的时间去处理信号,但是一定需要某种方式去记录(记录的方式通过对进程的位图做出改变)下来这个信号已经产生(),程序产生信号的方式:键盘输入,程序本身的异常。

3,信号处理

1,默认行为

提前安排好信号的处理方式(终止,暂停,继续运行等)。

2,自定义行为

程序员自己处理信号(自定义信号要做什么)

3,忽略信号

注意忽略信号并不是不处理,而是处理方式就是忽略。

二,信号如何发送和怎么记录

1,信号如何发送

进程收到信号,本质是存储信号的位图发生改变,只有操作系统有资格修改进程的位图,操作系统作为进程的管理者,有绝对的资格修改进程的task_struct中的位图,信号的发送方式有多种。

2,信号的记录

进程收到信号不一定直接处理,如果没有被处理,那这个信号就要被记录下来,等待合适的时间去处理,此时就需要数据结构去保存数据,位图就是用来记录信号数据的,通过对比特位的改变就能实现记录信号。多次相同信号输入,只记录一次。

三,信号在内核中如何表示的

信号在进程PCB块中会存在一个信号存储的位图,使用Block位图存储信号是否阻塞,pending位图用来存储信号是否被触发,handler处理方法,有默认,忽略,自定义。 

产生信号->信号未决->信号递达

一般信号执行的方式:

发送信号->修改pending->时间合适->检查block->对应信号未被block->开始递达

我们试着使用信号操作集函数实现对信号的捕捉

#include<stdio.h>
#include<signal.h>
#include<unistd.h>
void handler(int signo)
{
	printf("get a %d signal\n",signo);
}
void printpending(sigset_t *pending)
{
	 int = 1;    
	for(; i <= 31; i++)
	{
	    if(sigismember(pending, i))//判断指定信号在没在信号集里
		{
	        printf("1 ");
	    }
	    else
		{
	    	printf("0 ");
	    }
	    }
	    printf("\n");
}
int main()
{
	signal(2,handler); 
	sigset_t set oset;//用户定义空间变量 
	sigemptyset(&set);//初始化set和oset使得成为一个确定的数 
	sigemptyset(&oset);
	sigaddset(&set,2);//将二号信号加入信号集//SIGINT
	sigprocmask(SIG_SETMASK,&set,&oset);//阻塞二号信号
	
	
	sigset_t pending;
	int count=0;
	while(1)
	{
		sigemptyset(&pending);
		sigpending(&pending);//读取未决信号集,通过pending参数传出
		printpending(&pending);	
		sleep(1);
		count++;
		if(count==10)
		{
			sigprocmask(SIG_SETMASK, &oset, NULL); //恢复曾经的信号屏蔽字
			  printf("恢复信号屏蔽字\n");	
		}	
	} 
	 
	return 0;
}

 就可以看到信号在接受到的时候,二号信号对应的比特位为1.

四,信号的捕捉

1,内核如何实现信号捕捉

如果信号的处理动作是用户自定义函数,在信号递达时就调用这个函数,这称为捕捉信号。

举例如下: 用户程序注册了SIGQUIT信号的处理函数sighandler。 当前正在执行
main函数,这时发生中断或异常切换到内核态。 在中断处理完毕后要返回用户态的main函数之前检查到有信号SIGQUIT递达。 内核决定返回用户态后不是恢复main函数的上下文继续执行,而是执行sighandler函 数,sighandler和main函数使用不同的堆栈空间,它们之间不存在调用和被调用的关系,是两个独立的控制流程。 sighandler函数返回后自动执行特殊的系统调用sigreturn再次进入内核态。 如果没有新的信号要递达,这次再返回用户态就是恢复main函数的上下文继续执行了

如下图所示:

实际上我们在记录的时候可以如下记录状态的切换

2,为什么需要状态切换 

在内核态的时候识别信号可以被捕捉,理论上可以直接访问用户态的代码,但是绝对不能这样设计。

因为如果信号处理函数中存在一些非法代码,而此时我们的状态是内核态,有非常大的权限,能够处理这些非法代码,容易造成错误,所以需要切换到用户态再去实现代码。

3,sigaction

#include <signal.h>
int sigaction(int signo, const struct sigaction *act, struct sigaction *oact);

sigaction函数可以读取和修改与指定信号相关联的处理动作。调用成功则返回0,出错则返回- 1。signo是指定信号的编号。若act指针非空,则根据act修改该信号的处理动作。若oact指针非空,则通过oact传出该信号原来的处理动作。act和oact指向sigaction结构体:

使用方法如下:

struct sigaction act, oact;

void handler(int signo)
{
   printf("get a signal: %d\n", signo);
   sigaction(SIGINT, &oact, NULL);//恢复成默认的信号处理
}

int main()
{
   memset(&act, 0, sizeof(act));
   memset(&oact, 0, sizeof(oact));

   act.sa_handler = handler;
   act.sa_flags = 0;
   sigemptyset(&act.sa_mask);

   sigaction(SIGINT, &act, &oact);
   while(1){
       printf("I am a process!\n");
       sleep(1);
   }
   return 0;
}

五,可重入函数

不可重入的函数:

1,调用了malloc和free,因为malloc也是使用全局链表来管理堆的

2,调用了标准I/O库函数。标准I/O库的很多实现都以不可重入的方式使用全局数据结构

六,volatile关键字

 int flag = 0;

void handler(int signo)
{
   printf("get %d signo!\n", signo);

   flag = 1;
}

int main()
{
   signal(2, handler);
   while(!flag);
   printf("Proc Normal Quit!\n");
   return 0;
}

在运行这个代码时,会发现当键入ctrl+c时,程序并不能正常退出,这是因为编译器的优化问题,将主函数的flag优化到寄存器里面,而handler函数的flag放在内存中,导致handler不能改变flag的值,为了解决这个问题,加入了volatile关键字避免将flag优化至寄存器里面。

volatile 作用:保持内存的可见性,告知编译器,被该关键字修饰的变量,不允许被优化,对该变量的任何操作,都必须在真实的内存中进行操作

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

想找后端开发的小杜

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

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

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

打赏作者

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

抵扣说明:

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

余额充值