信号保存和处理

把上一篇回顾一下吧:共享内存区是最快的IPC形式。一旦这样的内存映射到共享它的进程的地址空间,这些进程间数据传递不再涉及到内核,进程不再通过执行进入内核的系统调用来传递彼此的数据

共享内存的数据结构:

struct shmid_ds 
{        struct ipc_perm shm_perm;       /* operation perms */    int shm_segsz;                  /* size of segment (bytes) */    __kernel_time_t shm_atime;      /* last attach time */    __kernel_time_t shm_dtime;      /* last detach time */    __kernel_time_t shm_ctime;      /* last change time */    __kernel_ipc_pid_t shm_cpid;    /* pid of creator */    __kernel_ipc_pid_t shm_lpid;    /* pid of last operator */    unsigned short shm_nattch;      /* no. of current attaches */    unsigned short shm_unused;      /* compatibility */    void *shm_unused2;              /* ditto - used by DIPC */    void *shm_unused3;              /* unused */
};

shmget函数

功能:用来创建共享内存

原型

int shmget(key_t key, size_t size, int shmflg);

参数

key:这个共享内存段名字

size:共享内存大小

shmflg:由九个权限标志构成,它们的用法和创建文件时使用的mode模式标志是一样的返回值:成功返回一个非负整数,即该共享内存段的标识码;失败返回-1

 shmat函数

功能:将共享内存段连接到进程地址空间

原型

void *shmat(int shmid, const void *shmaddr, int shmflg);

参数

shmid: 共享内存标识

shmaddr:指定连接的地址

shmflg:它的两个可能取值是SHM_RND和SHM_RDONLY

返回值:成功返回一个指针,指向共享内存第一个节;失败返回-1

 shmaddr为NULL,核心自动选择一个地址

shmaddr不为NULL且shmflg无SHM_RND标记,则以shmaddr为连接地址。

shmaddr不为NULL且shmflg设置了SHM_RND标记,则连接的地址会自动向下调整为SHMLBA的整数倍。公式:shmaddr - (shmaddr % SHMLBA)

shmflg=SHM_RDONLY,表示连接操作用来只读共享内存

shmdt函数

功能:将共享内存段与当前进程脱离

原型

int shmdt(const void *shmaddr);

参数

shmaddr: 由shmat所返回的指针

返回值:成功返回0;失败返回-1

注意:将共享内存段与当前进程脱离不等于删除共享内存段

 shmctl函数

功能:用于控制共享内存

原型

int shmctl(int shmid, int cmd, struct shmid_ds *buf);

参数

shmid:由shmget返回的共享内存标识码

cmd:将要采取的动作(有三个可取值)

buf:指向一个保存着共享内存的模式状态和访问权限的数据结构返回值:成功返回0;失败返回-1

 

消息队列 

消息队列提供了一个从一个进程向另外一个进程发送一块数据的方法

每个数据块都被认为是有一个类型,接收者进程接收的数据块可以有不同的类型值

IPC资源必须删除,否则不会自动清除(重启可以)system V IPC资源的生命周期随内核

信号量

五个概念捏

多个执行流(进程)能看到的一份资源是共享资源

被保护起来的资源是临界资源(同步和互斥)

进程互斥

由于各进程要求共享资源,而且有些资源需要互斥使用,因此各进程间竞争使用这些资源,进程的这种关系为进程的互斥

系统中某些资源一次只允许一个进程使用,称这样的资源为临界资源或互斥资源

在进程中涉及到互斥资源的程序段叫临界区

IPC资源必须删除,否则不会自动清除(重启可以)system V IPC资源的生命周期随内核

互斥:任何时刻只有一个进程在访问共享资源

 资源要被程序员访问的,通过代码访问,代码 = 访问共享资源的代码(临界区) + 不访问共享资源的代码(非临界区)

所谓的对共享资源进行保护(临界资源),本质是对访问共享资源的代码进行保护(临界区)

进入临界区加锁,出了临界区要解锁捏

对于信号量理论的理解

信号量,信号灯是为了保护临界资源的(code)

信号量:本质是一个计数器

看电影买票的本质是对资源的预定机制

所以流程就很明了了

先买票

再让执行流和资源进行一一对应(程序员编码实现)

电影院相当于临界资源(共享资源)

买票相当于申请信号量

总的票数:信号量的初始值

申请信号量的本质是对公共资源的一种预定机制

申请信号量 -- 访问共享内存 -- 释放信号量

对共享资源的整体使用是资源只有一个

计数只有1 or 0的被称作二元信号量,互斥

不能用一个全局变量来当做计数器

为什么捏?

全局变量能被所有进程看到么?

不能捏

根本不能实现我们的要求捏,不是原子的

IPC信号量和共享内存、消息队列一样,要让不同的进程看到同一个计数器

信号量也是一个公共资源,保护临界资源安全的前提是自己是安全的

信号量操作

信号量--要是安全的 --> P

信号量++也要是安全的 --> V

PV操作通过安全保证原子性(以结果为导向,就比如鸡婆的棕褐色猎犬打炉石,打了一晚上,但是最后switch只看他是否上去分了,不会因为他哪局运气不好操作失误卡掉而同情它,也不会做出干预,只看最后的结果)

申请信号量用什么接口捏?

int semget(key_t key,int nsems,int semflg);

信号量集由数组来维护 

信号量不用了怎么办呢?

int semctl(int semid, int semnum, int cmd, ...);

op是对PV操作的封装 

int semop(int semid, struct sembuf *sops, size_t nsops);

 

信号量指令
ipcs -s

 删掉指定的信号量:

ipcrm -s semid

 OS是如何把共享内存,消息队列,信号量统一管理起来的呢?

struct ipc_id_ary
{int size;struct kern_ipc_pern* p[0];...
}

把它们的第一个元素都存到struct kern_ipc_perm *XXX[n],就意味着我们把IPC的资源统一管理了

shmid就是数组的下标

所以检测是否冲突只需要遍历数组来检查

这种技术叫多态!

IPC_perm里必须要有字段指向对应的类型

信号

信号和信号量有什么区别。。。

有什么关系

两个没什么关系,就跟鸡婆的棕褐色猎犬和炉石传说高手没什么关系一样,八竿子打不到一块

信号在生活中随时可以产生,信号的产生和进程是异步的

进程能认识信号,可以识别并处理信号

可以把到来的信号暂不处理

在合适的时候再处理

1~31是普通信号,后面是实时信号

信号是Linux系统提供的一种向指定进程发送特定事件的方式,做识别和处理

信号的产生是异步的

异步就是,比如墨墨酱正在上课,但是她的外卖到了,为了避免别人偷她外卖,所以她派遣励志轩去帮她取外卖,墨墨酱上她的课,同时励志轩帮她取外卖,互不耽误

所以总结一下就是信号是Linux提供的一种,向指定进程发送特定事件的方式,做识别和处理

信号处理有三个动作:默认动作、忽略动作、自定义处理(信号的处理)

使用信号最直观的一个接口就是

man 7 signal

sighandler_t signal(int signum,sighandler_t handler);

 

对信号的自定义捕捉只需要捕捉一次,后续就会一直有效

#include<iostream>
#include<signal.h>
#include<unistd.h>void hander(int sig)
{std::cout << "get a sig" << sig <<std::endl;
}int main()
{signal(2,hander);while (true){std::cout << "hello world,pid: " << getpid() <<std::endl;sleep(1);}return 0;
}

 

可以发现捏

kill -2就相当于是Ctrl+c了 

信号产生是通过kill命令向进程发送信号捏

键盘也可以发送信号

还有一种方式可以产生信号:系统调用

我们如何理解信号的发送与保存呢?

进程有对应的task_struct,这是成员变量,而我们是通过位图来保存收到的信号的

uint32_t signals;

 发送信号就是修改指定进程PCB中的信号的指定位图

内核数据结构对象,只有OS有资格修改

祝贺我姐喜提新键盘咯

看着感觉很像那种敲起来像什么奶油轴的声音

 使用kill也是可以实现系统调用的捏:

 来演示一下:

testsig.cc:

#include<iostream>
#include<signal.h>
#include<sys/types.h>
#include<unistd.h>//./mykill 2 pid
int main(int argc,char *argv[])
{if(argc != 3){std::cerr << "Usage: " << argv[0] << "signum pid" << std::endl;return 1;}pid_t pid = std::stoi(argv[2]);int signum = std::stoi(argv[1]);kill(pid,signum);
}

process.cc:

#include<iostream>
#include<unistd.h>
#include<signal.h>void hander(int sig)
{std::cout << "get a sig" << sig <<std::endl;
}int main()
{signal(2,hander);while (true){std::cout << "hello world,pid: " << getpid() << std::endl;sleep(1);}return 0;
}

makefile:

 其实每次感觉很没必要,但是那是代码哎

交一下吧,谁说

makefile不算代码呢

.PHONY:all
all: client serverclient:client.ccg++ -o $@ $^ -std=c++11
server:server.ccg++ -o $@ $^ -std=c++11
.PHONY:clean
clean:rm -rf client server

 除了kill之外还有别的接口:

raise是给自己当前的进程发送信号:

#include<iostream>
#include<signal.h>
#include<sys/types.h>
#include<unistd.h>void hander(int sig)
{std::cout << "get a sig" << sig <<std::endl;
}int main()
{int cnt = 0;signal(3,hander);while (true){sleep(2);raise(3);}
}

 

还有个接口:abort

 

abort是终止进程,可以向进程发送指定信号

 

#include<iostream>
#include<cstdlib>
#include<signal.h>
#include<sys/types.h>
#include<unistd.h>void hander(int sig)
{std::cout << "get a sig" << sig <<std::endl;
}int main()
{int cnt = 0;signal(3,hander);while (true){sleep(2);abort();}
}

 

abort允许捕捉,但是进程还是要终止(因为abort就是用于异常终止的)

 那如果我把所有信号都捕捉完,是不是就不能终止我的进程了?

铁子你在想什么

9号信号不允许自动捕捉啊

直接

kill -9 pid

就老实了

 信号是由他们产生的,那么真正发送信号的是谁?

只有一个:操作系统!

因为发送信号的本质是修改进程PCB中的位图,而只有操作系统有这个资格这样做

软件条件要是管道的读关闭,写一直进行的话

操作系统就会向写进程发送sigpipe信号

我们还可以通过一个函数:alarm,来充当一个闹钟的作用

#include<iostream>
#include<cstdlib>
#include<signal.h>
#include<sys/types.h>
#include<unistd.h>void hander(int sig)
{std::cout << "get a sig" << sig <<std::endl;exit(0);
}int main()
{int cnt = 1;signal(SIGALRM,hander);alarm(1);       //设置一秒后的闹钟while (true){std::cout << "cnt: " << cnt << std::endl;cnt++;}return 0;
}

 

又是新bug

假如不打印呢?

#include<iostream>
#include<cstdlib>
#include<signal.h>
#include<sys/types.h>
#include<unistd.h>int cnt = 1;void hander(int sig)
{std::cout << "cnt: " << cnt << "get a sig: " << sig << std::endl;exit(1);
}int main()
{signal(SIGALRM,hander);alarm(1);       while (true){cnt++;}return 0;
}

 

我们可以发现,IO是一件很慢的事情 

如果单纯++是内存级的数据递增,但是要是打印到显示器上,显示器毕竟是外设,我们还用的云服务器,当云服务器上代码跑完再推送到本地,这个工作量是不可估量的

就拿中指举例,我竖中指再拍照片,蓝色米老鼠存照片,再添加为表情包并发送,这个工作量是难以估量的,所以建议大家直接竖中指

我们的电脑里面有一块小电池,电脑没电了它都有电,专门用来看时间的

而针对于闹钟,操作系统要对它做管理

闹钟是个结构体对象

struct alarm
{time_t expired;    //未来的时间 = seconds + Now();pid_t pid;fuc_t f;...
}

 用最小堆进行管理捏

alarm(0)表示取消闹钟,返回值表示上一个闹钟的剩余时间

闹钟默认只触发一次

#include<iostream>int main()
{int *p = nullptr;*p = 100;return 0;
}

致命三连问:程序为什么会崩溃?崩溃了为什么会退出?可不可以不退出?

是因为非法访问导致OS给进程发送信号啦!!!

那我们怎么证明呢?

还是老样子,对信号做自定义捕捉就好啦

#include<iostream>
#include<cstdlib>
#include<signal.h>
#include<sys/types.h>
#include<unistd.h>void hander(int sig)
{std::cout << "get a sig: " << sig << std::endl;exit(1);
}int main()
{signal(SIGSEGV,hander);// int a = 10;// a /= 0;int *p = nullptr;*p = 100;return 0;
}

对于野指针,信号是11

对于非法的计算(比如除以0),信号是8 

程序崩溃的时候也会向进程发送信号

我崩溃的时候也会向chat发送信号

进程会给OS发信号,最好是退出捏

CPU会帮我们进行两种计算

有种寄存器叫eflag,状态寄存器,是 x86 架构中用于保存处理器标志的寄存器

它是一个 32 位寄存器,其中的每一位代表了处理器的某个状态或控制标志

MMU 主要指的是 “内存管理单元”(Memory Management Unit),它是计算机中的一个重要硬件组件,负责管理计算机系统中的内存。MMU 主要有以下功能:

  1. 地址转换:将虚拟地址转换为物理地址。这对于虚拟内存系统非常重要,因为程序通常使用虚拟地址,而计算机硬件则使用物理地址
  2. 内存保护:通过设置访问权限,防止程序或进程非法访问或修改其他程序或进程的内存区域
  3. 缓存控制:优化内存访问速度,减少对主内存的访问需求

OS是软硬件资源的管理者,要随时处理这种硬件问题,所以会向进程发送信号

出问题了告知你

CR3寄存器保存的是页表的起始地址,还有个寄存器是CR2,当虚拟地址向物理内存中转化失败的时候,失败信息会存放到CR2寄存器里(CR2:页故障线性地址寄存器)

栈溢出是越界捏

core和term

term是异常终止,core也是异常终止,但是会帮我们形成一个debug文件

但是我们运行有问题的程序,却查不到core

这是因为我们核心转储可能被禁用了:

ulimit -c

这个可以查看当前核心转储功能有没被启用

 

为0就是没有启用,可以通过这个命令来启用:

ulimit -c unlimited

 

几个梗图:

 

我们的编译要是在-g下的,这样可以获得更多调试信息

而core的生成不是在当前目录下的,这样可以让core生成在当前目录:

echo "core.%e.%p" | sudo tee /proc/sys/kernel/core_pattern

 

这样就生成了 ,可以用gdb辅助我们进行错误的排查

gdb的具体使用方法都总结在这篇博客里了:

炫酷gdb-CSDN博客icon-default.png?t=O83Ahttps://blog.csdn.net/chestnut_orenge/article/details/138551058 为什么我的显示出来是这个

我真的

懒得喷了

这谁能看得懂啊,我讲个蛋我也不会我下了

我真红温了

爱谁用谁用

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/421597.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Pycharm使用debug运行时,一直显示collecting data...,但是变量一直显示不出来,显示超时

一、问题&#xff1a; 二、解决办法 1.File—>Setting 2.Build---->Python Debugger 3.勾选Gevent compatible &#xff0c;然后Apply 三、解释Gevent compatible 1.在 PyCharm 中&#xff0c;Gevent compatible 通常与 gevent 库的兼容性设置有关。gevent 是一个基于协…

NC字典树的实现

系列文章目录 文章目录 系列文章目录前言 前言 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站&#xff0c;这篇文章男女通用&#xff0c;看懂了就去分享给你的码吧。 描述 字典树又称为…

Ubuntu系统修改静态IP

1.先查看一下我们的ip rootcaiji:~# ip a 2.查看此时的网卡配置文件 rootcaiji:~# cat /etc/netplan/00-installer-config.yaml # This is the network config written by subiquity network: ethernets: ens33: dhcp4: true version: 2 此时可以看出来dhcp…

SpringCloud Alibaba入门简介

1、诞生 2018.10.31&#xff0c;Spring Cloud Alibaba 正式入驻了 Spring Cloud 官方孵化器&#xff0c;并在 Maven 中央库发布了第一个版本。 2、是什么&#xff0c;去哪下 官网&#xff1a;Spring Cloud Alibaba官网_基于Springboot的微服务教程-阿里云-阿里云Spring Cloud …

【论文阅读笔记】Tackling the Generative Learning Trilemma with Denoising Diffusion GANs

【论文阅读笔记】Tackling the Generative Learning Trilemma with Denoising Diffusion GANs Introduction方法 使用传统GANS建模去噪分布理解模式覆盖率 Paper&#xff1a;https://arxiv.org/abs/2112.07804 Code&#xff1a;https://github.com/NVlabs/denoising-diffusion-…

Docker启动Mysql镜像报错问题?

docker中启动mysql镜像报错如下&#xff1a;ls: cannot access /docker-entrypoint-initdb.d/: Operation not permitted 百度上查到了很多解决方案&#xff0c;也咨询了很多大佬&#xff0c;加权限&#xff0c;改用户&#xff0c;均无果。最终在阿里巴巴上找到了解决方案&…

[论文笔记]ChatQA: Surpassing GPT-4 on Conversational QA and RAG

引言 今天来看一下上篇论文笔记中反复介绍的 ChatQA: Surpassing GPT-4 on Conversational QA and RAG。 为了简单&#xff0c;下文中以翻译的口吻记录&#xff0c;比如替换"作者"为"我们"。 我们介绍了 ChatQA&#xff0c;这是一个模型套件&#xff0c;一…

算法设计(一)

1.汉诺塔 介绍 汉诺塔&#xff08;Hanoi Tower&#xff09;:它描述了如何将一堆大小不同、穿在一根柱子上的盘子移动到另一根柱子上&#xff0c;同时满足以下规则&#xff1a; 每次只能移动一个盘子。 每个移动盘子时&#xff0c;大的盘子不能放在小的盘子上面。 可以使用一根…

curl和ping

curl获取页面内容&#xff0c;ping测试连通 curl和ping是两个在网络环境中常用的命令行工具&#xff0c;但它们的目的和应用场景有很大的不同。 curl 用途&#xff1a;curl是一个命令行工具&#xff0c;用于传输数据&#xff0c;支持多种协议&#xff0c;包括HTTP、HTTPS、FT…

1. 运动控制指令概要(omron 机器自动化控制器)

机器自动化控制器——第一章 运动控制指令概要 1-1 运动控制指令PLCopen运动控制用功能块运动控制指令概要▶ 运动控制指令的种类▶ 状态变化▶ 运动控制指令的启动和状态▶ 异常处理▶ 执行运动控制指令时输入变量的变更(指令重启)▶ 通过选择缓存模式执行指令多重启动▶ 通过…

【生成模型系列(初级)】嵌入(Embedding)方程——自然语言处理的数学灵魂【通俗理解】

【通俗理解】嵌入&#xff08;Embedding&#xff09;方程——自然语言处理的数学灵魂 关键词提炼 #嵌入方程 #自然语言处理 #词向量 #机器学习 #神经网络 #向量空间模型 #Siri #Google翻译 #AlexNet 第一节&#xff1a;嵌入方程的类比与核心概念【尽可能通俗】 嵌入方程可以…

C语言程序设计——函数(一)

一、概述 一个较大的程序可分为若干个程序模块,每一个模块用来实现一个特定的功能。在高级语言中用子程序实现模块的功能。子程序由函数来完成。一个C程序可由一个主函数和若干个其他函数构成。 由主函数调用其他函数,其他函数也可以互相调用。同一个函数可以被一个或多个函…

C语言-数据结构 无向图克鲁斯卡尔算法(Kruskal)邻接矩阵存储

相比普里姆算法来说&#xff0c;克鲁斯卡尔的想法是从边出发&#xff0c;不管是理解上还是实现上都更简单&#xff0c;实现思路&#xff1a;我们先把找到所有边存到一个边集数组里面&#xff0c;并进行升序排序&#xff0c;然后依次从里面取出每一条边&#xff0c;如果不存在回…

99.游戏安全项目-可见数据的搜索与技巧

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 内容参考于&#xff1a;易道云信息技术研究院 上一个内容&#xff1a;98.游戏的启动与多开-分析与实现多开器 下图中红框位置显示的数据&#xff0c;只有下图…

横版闯关手游【全明星时空阿拉德】Linux手工服务端+运营后台+双app端

横版闯关手游【时空阿拉德】&#xff08;【全明星阿拉德】&#xff09;阿拉德系列2022整理Linux手工服务端余额充值后台安卓苹果双端。 运营后台看目录结构是thinkphp开发的。 代码免费下载&#xff1a;百度网盘

再识Clip

来源 CLIP损失函数的理解-CSDN博客 Simple Implementation of OpenAI CLIP model: A Tutorial | Towards Data Science 【小白】一文读懂CLIP图文多模态模型_clip模型-CSDN博客 从 CLIP 聊聊多模态自监督学习新范式 - 知乎 (zhihu.com) CLIP 论文逐段精读【论文精读】_哔哩…

BC173 牛牛逆序输出(c 语言)

1.// 描述 //牛牛在尝试把一个整数逆序地输出。 //输入描述&#xff1a; //输入一个正整数 n。保证个位数不是 0 //输出描述&#xff1a; //逆序输出这个正整数。 //2345 //5432 2.我们先输入n,然后我们进行取余&#xff0c;然后将余数存储起来在arr中&#xff0c;然后除10。…

串口接收不到数据之电阻虚焊bug分析思路

单片机和EC移远通信模块进行通信&#xff0c;相同的代码运行在相同的硬件上&#xff0c;但是一个能联网&#xff0c;一个因为没有EC的应答连不上网。 开始分析&#xff0c;排除软件问题&#xff0c;给EC模块发为什么没应答&#xff1f; 1.发送失败 2.接收失败 排除情况2&#x…

redis底层—网络模型

1.用户空间和内核空间 2.阻塞IO 3.非阻塞IO 4.IO多路复用 select模式的三个问题&#xff1a; 能监听的FD最大不超过1024 每次select都需要把所有要监听的FD都拷贝到内核空间 每次都要遍历所有FD来判断就绪状态 poll模式的问题&#xff1a; poll利用链表解决了select中监听FD上限…

基于RFID技术的光交箱哑资源智能化管理方案

一、现状 &#xff08;一&#xff09;现状与挑战 在当前通信网络基础设施中&#xff0c;哑资源如光缆接头、跳线等在网络中占据着重要地位。然而&#xff0c;传统的哑资源管理方式存在诸多问题&#xff0c;一方面&#xff0c;管理主要依赖人工记录和定期巡检&#xff0c;效率…