IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 系统运维 -> [linux] 进程间信号 -> 正文阅读

[系统运维][linux] 进程间信号

信号在生活中无处不在,上下课铃,红绿灯,闹钟等,这一切都是信号,可是我们是如何识别信号的呢?无非就是有人定义将信号与意义绑定,并灌输。在操作系统中也存在信号,那么我们一起来看看吧
在这里插入图片描述

1 理解信号

信号不管是在生活中还是在操作系统中其实都可以简单看为三部分

  1. 是什么
  2. 为什么
  3. 怎么处理

而在操作系统层面来看并不需要知道为什么(毕竟信号也是工程师定义的),他只需要知道是啥信号和收到信号后要如何处理,其实生活中收到信号也是如此,过马路红灯停,绿灯行,并不会有人问为啥。


1.1 见识Linux中的信号

在linux中查看信号需要用到命令 kill -l,一共62个信号,1~31为默认信号,24~64为实时信号
在这里插入图片描述

浅谈: 默认信号 VS 实时信号

普通信号会丢失,实时信号不会丢失,也就是是否要存储信号,后文会提

在Linux下的全部信号都是宏,也就是一个标志位,这样做的目的节省空间,用一个bit位标识一种状态,默认信号存放在该路径下/usr/include/bits/signum.h

在这里插入图片描述

1.2 如何产生信号

一切事情都是有前因后果的,当然信号也是,先要如何产生才可以知道如何处理

  1. 键盘产生
  2. 命令行向进程发送信号
  3. 调用函数向os发送请求
  4. 代码出错(访问硬件出错)

键盘产生

ctrl+c 终止进程 ctrl+\ 终止进程并保存core文件 ,ctrl+z挂起一个文件,他们其实和信信号列表一一对应,后文信号捕捉验证
在这里插入图片描述


命令行向进程发送信号

使用命令 kill -信号(数字or宏名) 进程pid
在这里插入图片描述

调用函数向os发送请求

其实就是和os说快给我发信号,C语言接口alarm(延迟xx秒让os发送14号信号给该进程)abort(让os给当前发6号信号)raise(指定让os发送x号信号)kill(给别的进程发送信号)

alarm
代码:

int main()
{
  alarm(5);
  int count=0;
  while(1)
  {

    cout<<count++<<" "<<getpid()<<endl;
    sleep(1);
  }
  return 0;
}

结果:
在这里插入图片描述

kill
在这里插入图片描述

代码:

#include<iostream>
#include<csignal>
#include<unistd.h>
#include<sys/types.h>
using namespace std;


int main()
{
  kill(1213,1);
}

结果:
在这里插入图片描述

代码出错(访问硬件出错)

子进程退出的时候可以用wait函数等待回收他的资源,且也可以知道他的退出码,core dump ,信号 。
在这里插入图片描述

代码:

#include<iostream>
#include<csignal>
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>

using namespace std;


int main()
{
  pid_t id=fork();
  while(id==0)
  {
    //child
    int count=0;
    while(count!=5)
    {
      count++;
      cout<<"I am child proc"<<endl;
      sleep(1);
    }
    //除0错误
	//int a =1;
    //int b=0;
    //a/=b;

    //野指针
    int *c=0x000000;
    *c=1;
  }
  int status=0;
  waitpid(id,&status,0);
  cout<<(status&0x7f)<<endl;
  return 0;
}

结果:
在这里插入图片描述

os是如何知道代码出错而发对应的信号呢?

除0对应的硬件 == cup中的状态寄存器
野指针 == 内存/页表MMU
os是软硬件的管理者,自然就知道哪里出错,在根据硬件在对进程发送信号

core dump


1.3 信号的处理

在现实中我们处理信号一般有三种方式

  1. 默认(识别信号马上处理 , 红绿灯)
  2. 忽略 (识别信号不处理,打游戏妈妈叫吃饭)
  3. 捕捉自定义 (识别后用自己的方法,听到闹钟声跳个舞🐶🐶)

在操作系统中也是如此处理信号也是以上三种方式,且也知道一个进程收到信号不一定马上处理那么不处理就要保存起来(该进程的PCB中)。按照老的套路先描述在组织,这里的组织方式就是一个位图

在这里插入图片描述

当os发送信号给进程时,看信号是xx号并在对应的pending位图中,把xx号位置设为1 ,再看看block位图xx号位置是否设为1,如果为1屏蔽信号,不然直接执行方法。其实信号被屏蔽还有一个专业的名词(未决),信号没有被屏蔽执行的方法(递达)

递达信号流程图
在这里插入图片描述


1.3.1 屏蔽信号与获取pending

在C语言中有一个类型sigset_t 可以表示一个每个信号的有效与无效,也就是一个位图,我们可以用它和信号集操作函数等来告诉os屏蔽那些信号

信号集操作函数

 #include <signal.h>
int sigemptyset(sigset_t *set);//初始化 ”位图“ 为0
int sigfillset(sigset_t *set);//初始化 ”位图“ 为1
int sigaddset (sigset_t *set, int signo);//给 “位图”指定位置为1
int sigdelset(sigset_t *set, int signo);//给 “位图”指定位置为0
int sigismember(const sigset_t *set, int signo);//判断 ”位图“指定位置是否为1

上述的接口都是语言接口,也就说明,我们还没有告诉os要屏蔽那个信号,那么就要用到系统接口,sigprocmask

sigprocmask使用介绍
在这里插入图片描述

使用这个接口就可以让os吧pcb中block变成自己所设置位图的样子,屏蔽信号

sigpending使用介绍

在这里插入图片描述
输入形参数,获取pending当前状态

代码
实现屏蔽信号获取pending,删除屏蔽,抵达信号

#include<iostream>
#include<unistd.h>
#include<signal.h>
#include<unistd.h>
using namespace std;


void showpending(sigset_t * set)
{
	for(int i =1; i<=31;i++)
	{
		if(sigismember(set,i))
		{
			cout<<'1';
		}
		else
		{
			cout<<'0';
		}
	}
	cout<<endl;
}
int main()
{
	sigset_t set,oset;
	sigemptyset(&set);
	sigemptyset(&oset);


	sigaddset(&set,2);
	sigprocmask(SIG_SETMASK,&set,&oset);

	int count=0;
	while(1)
	{
		sigpending(&set);
		showpending(&set);
		sleep(1);
    count++;
		if(count==7)
		{
			break;
		}
	}


	return 0;
}

结果:


在这里插入图片描述


1.3.2 信号捕捉(自定义处理)

上述说过信号的处理方式, 默认,忽略,捕捉,其实捕捉就是自定义信号(递达),也就是修改pcb中的hander函数数组中的方法,系统接口signal ,sigaction

接口介绍:
,

接口使用

signal

#include<iostream>
#include<unistd.h>
#include<signal.h>
#include<unistd.h>
using namespace std;


void hander(int signo)
{
  cout<<"signo: "<<signo<<endl;
}
int main()
{
  signal(2,hander);
  int count=0;
  while(1)
  {
    cout<<count++<<endl;
    sleep(1);
  }



  return 0;
}

结果:
在这里插入图片描述


sigaction

#include<iostream>
#include<unistd.h>
#include<signal.h>
#include<unistd.h>
using namespace std;


void hander(int signo)
{
  cout<<"signo: "<<signo<<endl;
}
int main()
{

  //signal(2,hander);
   struct sigaction act;
   struct sigaction oact;
  act.sa_handler=hander;
  sigaction(2,&act,&oact);
  int count=0;
  while(1)
  {
    cout<<count++<<endl;
    sleep(1);
  }



  return 0;
}

结果:
在这里插入图片描述

既然可以屏蔽捕捉信号,那我全部屏蔽我这个进程不就杀不死了吗?

既然你可以想到,没错工程师也想到了,在linux下有SIGKILL与SIGTOP信号是无法捕捉的和屏蔽,专门防止你小心思


问信号时如何捕捉的呢?

抽象理解,捕捉函数是一个地雷,而触发的条件就是信号。

回顾进程虚拟地中空间:
在这里插入图片描述

之前说每个进程都有自己的一张独有的页表,其实还不太准确,其实有俩张一张是用户级页表,一张是系统级页表(每个进程共享),在执行代码时,没有遇到系统接口前用的都是用户级页表,当执行到系统接口时转换为系统页表

图解捕捉捕捉的流程图:
捕捉的过程其实很像数学中的一个符号

在这里插入图片描述


1.4 SIGCHILD

之前说过子进程退出的时候父进程会回收子进程,一方面是防止内存泄漏,一方面是获取子进程的退出结果。但等待,父进程就在阻塞等待里(or非阻塞轮询),着都让父进程无法一心一意的执行自己的代码?那么如何解决呢?

解决方案

子进退出的时候会给父进程发送一个信号SIGCHILD,🙉🙉🙉,那配合signal不就…………子进程退出发送信号,捕捉,改变SIGCHILD的函数实现方法

代码:

using namespace std;

void hander(int signo)
{
	cout<<signo<<endl;
  pid_t id;
	while((id=wait(NULL))>0)
	{
		printf("wait pid %d success",id);
	}


}
int main()
{

	signal(17,hander);
	pid_t id =fork();
	if(id==0)
	{
		//child
		int count=4;
		while(count>0)
		{
			count--;
			cout<<count<<" "<<getpid()<<endl;
			sleep(1);
		}
		exit(1);
	}

	while(true)
	{
		cout<<"I am father proce"<<endl;
		sleep(1);
	}

	return 0;
}

结果:
在这里插入图片描述

  系统运维 最新文章
配置小型公司网络WLAN基本业务(AC通过三层
如何在交付运维过程中建立风险底线意识,提
快速传输大文件,怎么通过网络传大文件给对
从游戏服务端角度分析移动同步(状态同步)
MySQL使用MyCat实现分库分表
如何用DWDM射频光纤技术实现200公里外的站点
国内顺畅下载k8s.gcr.io的镜像
自动化测试appium
ctfshow ssrf
Linux操作系统学习之实用指令(Centos7/8均
上一篇文章      下一篇文章      查看所有文章
加:2022-06-06 17:33:28  更:2022-06-06 17:34:04 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/15 13:56:37-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码