Linux相关概念和易错知识点(25)(信号原理、操作系统的原理、volatile)

Linux:详解进程信号(信号的捕捉流程,信号的阻塞、volatile关键字)(二) 文章目录1. 信号的捕捉流程1.1 捕捉流程 前言:阅读的时候如有不懂的的地方,可以看我之前写的详解进程信号(信号的种类、产生、注册、注销以及信号的各种处理方式)(一) 1. 信号的捕捉流程 在讲信号的捕捉流程的时候,我们需要首先明确的一个问题是:信号的注册,是否与操作系统所维护的进程PCB有关? 在上一篇文章中也讲了,信号的注册实质是将tast_struct(PCB)结构体中的struct sigpending结构体变量,它所包含的sigset_t signal位图中所对应的那个信号的比特位置为1,然后 阅读详情

目录

1.信号的产生

(1)kill

(2)raise、abort

2.对block、pending、handler表的管理

(1)信号集(sigset_t)

(2)block表的管理

①操作相关的函数

②sigprocmask

(3)pending表的管理

(4)handler表的管理

3.操作系统的原理

(1)硬件中断

①中断控制器

②中断号

③保护现场、恢复现场

(2)时钟源

①主频

②时间片

(3)异常处理

(4)软中断

①软中断和硬件中断

②系统调用表

③缺页中断

④异常、陷阱

(5)用户态和内核态(重点)

①用户区、内核区

②用户态和内核态之间的切换

③函数跳转

(6)捕捉信号流程

①用户态和内核态的切换

②对状态切换的理解

③对执行流概念的深化

(7)volatile

①可重入函数

②volatile、编译器优化

4.信号拓展

(1)SIGCHLD

(2)SIGALRM


1.信号的产生

(1)kill

信号究竟是如何产生的?我们已经知道信号的各种上层规则,但对于信号的来源还不是很熟悉。

看一下下面的代码,就能很快理解了。

kill本身就是个系统调用,而不仅仅是一个指令。int kill(pid_t pid, int sig);就可以实现对特定的pid进程发送sig信号,当信号发送成功时返回0,失败时返回-1。

也就是说所谓的kill指令,底层还是kill函数系统调用(指令->系统调用)。因此我们可以理解,当bash进程要kill掉其子进程时,就是调用的kill函数实现的。如当管道的读端关闭,系统会直接杀掉进程,就是使用的kill发送SIGPIPE信号

(2)raise、abort

int raise( int )意思是谁调用,就给自己发送这个信号,也就是说raise(9)可以杀掉自己。

void abort( void )意思是谁调用,就给自己发送SIGABRT 6号终止信号。相当于raise(6)

2.对block、pending、handler表的管理

在介绍了三张表的功能和调用流程之后,我们需要进一步讲讲如何修改这三张表,因为信号从接收到发送的全过程都由这三张表控制,管理这三张表本质上就是在管理信号的处理。

(1)信号集(sigset_t)

未决(pending)和阻塞(block)表都可用相同类型来存储,因为它们本质都是位图。这个位图的结构体是sigsei_t,也称为信号集,这个类型在两张表有不同含义:在pending表表示是否有接收到该信号,在block表表示是否阻塞该信号。阻塞(block)信号集也叫做当前进程的信号屏蔽字(Signal Mask),这里的屏蔽是指阻塞。

我们只需记住信号集的本质是位图,是未决(pending)和阻塞(block)表中位图的专属类型。 

(2)block表的管理

注意以下的函数都是针对block表的信号集!

①操作相关的函数

首先,我们需要自己创建一个sigset_t的变量,再对这个位图进行如下处理:

int sigemptyset(sigset_t *set);将位图清0; int sigfillset(sigset_t *set);将位图填为全1

int sigaddset(sigset_t *set, int signum);添加对signum号信号的屏蔽(本质就是修改位图,将对应位改为1);int sigdelset(sigset_t *set, int signum);删除对signum号信号的屏蔽

上述返回值都是0为成功,-1为错误

②sigprocmask

接下来我们要让我们的改动生效,上述所有的改动都是用户自己的修改,并没有写到内核中去。

int sigprocmask(int how, const sigset_t *newset, sigset_t *oldset);

how由如下宏定义决定功能:SIG_BLOCK增加传入的newset中状态为1的信号的阻塞;SIG_UNBLOCK解除传入的newset中状态为1的信号的阻塞;SIG_SETMASK直接用newset覆盖block表中的位图。注意这个newset就是刚才我们进行各种处理后的sigset_t变量(输入型参数)。而oldset是输出型参数,是修改前的位图,帮助我们恢复原来的位图。

除了上述用法之外,sigprocmask(0, NULL, &oldset)可以获取当前的block表

下面的代码,我利用阻塞表阻塞了2号信号的处理,使得信号无法被处理

(3)pending表的管理

int sigpending(sigset_t *set);用于获取pending表,set是一个输出型参数,该函数只提供内核中的pending表而不提供修改。其返回值0表示成功,-1表示失败。

int sigismember(const sigset_t *set, int signum); 判断signum对应信号是否有效。pending和block表都可以用,因为它们的位图的数据类型一致。我们需要手动传入sigset_t,这需要我们使用sigpromask、sigpending获取当前block、pending表。其返回值是1为真,0为假,-1为错误

(4)handler表的管理

signal函数可以进行信号捕捉,进而修改handler表,这里提一句即可。

int sigaction(int signum, const struct sigaction* newact, struct sigaction* oldact);

对于这个结构体,通常flag设置为0,sa_handler设置为指定的void(int)函数指针,使用为sigaction(2, &act, &oldact),即将信号2的默认处理方式替换为自定义处理,并且得到一个oldact用于备份。

struct sigaction的sa_mask成员还可以顺便帮我们添加要屏蔽的信号,我们自己设置sigset_t,在后续调用sigaction函数时,除了相应pending表被修改,block表也会加上sa_mask里面的几个屏蔽的信号。

3.操作系统的原理

要进一步理解信号,我们要对OS进一步深挖,来解释为什么我们键盘输入信号后OS能够及时的处理?是否需要OS一直等待键盘输入?同步异步是如何实现的?

(1)硬件中断

OS怎么知道键盘输入数据了?是否需要OS一直等待键盘输入?事实上,OS是启动的第一个软件,它不会轮询设备,设备数量太多了,键盘、磁盘、显示屏等,而是外设提醒OS后OS再来处理。

①中断控制器

以键盘输入为例,键盘按下会首先触发硬件中断(由硬件电路实现),这个硬件中断的信号不会直接传给CPU(物理上键盘并没有直连CPU),而是传给中断控制器(和每个设备直连),中断控制器再向CPU发送信息,进而被OS获取。

注意中断控制器可不会关心键盘按什么键,它只会告诉CPU发生了中断,CPU也不会关心,它收到中断后只会告诉OS有外设准备好了,之后在OS的管理下,键盘给CPU传信息,进而实现给OS传信息。至于键盘输入了什么,那是OS之后需要干的事。

再以磁盘为例,当磁盘想要给进程发信息时,虽然磁盘的寻址需要时间,要定位要准备,但这段时间OS不管,继续执行自己的任务,仅当磁盘准备好后中断控制器直接向CPU发送信号,执行读取操作即可。这样,硬件和OS实现了并行执行。

这里我们就会发现,信号和硬件中断有相似之处,信号是纯软件模拟中断的行为,硬件中断是靠软硬结合实现的(绝大部分是硬件)。

②中断号

对于中断控制器而言,每个设备都对应一个中断号,中断控制器利用中断号触发高电平告诉CPU谁中断了。这些中断号OS明白对应哪些设备,此时OS就回去调用对应的处理方法。要管理这些处理方法,OS有一个中断向量表IDT,这是一个函数指针数组,中断号就相当于数组下标。当中断控制器告诉OS中断号后,OS直接由IDT调用中断服务处理中断。这些中断服务包括读取硬盘、网卡等。方法内容由OS自定或安装驱动确定,同时我们也要知道中断号和中断处理方法是相对固定的,是软硬结合共同维护的。

③保护现场、恢复现场

在OS接收到中断控制器的信号,确定要处理中断之后,OS会将当前CPU各种寄存器的数据保存在中断的上下文,方便后续处理。保存好寄存器数据后,OS就会根据中断向量表找方法,执行中断处理例程(利用中断号查表)。处理完后就会恢复现场,继续执行任务。

OS通过中断实现了不主动轮询外设。所有外设(不含内存,它是存储器)都是这么处理的。

(2)时钟源

进程可以在OS指挥下调度执行,那么OS自己被谁指挥呢?时钟源。

①主频

我们已经知道了所有外设的信息是如何进入进程被处理的了,其中有一个外设,每隔一段极短时间就会给CPU发硬件中断,这个外设就是时钟源,它具有一个固定的中断号,以及一个固定的中断服务:进程调度。时钟源会一直推动OS进行进程调度,OS就是基于不断中断,调用中断向量表工作的。现在时钟源已经被集成在CPU内部,时钟源的触发频率就是CPU主频的概念(如14900K的6GHZ)。主频速度越快,处理任何操作都会更频繁。

OS在时钟的推动下自行调度,相当于说OS可以不做任何事,启动之后直接让自己进入死循环,利用时钟和其它外设触发中断推着它进行运行,执行方法。

总结:对于OS来说,只要完全没有进程,它就陷在死循环中,但只要有进程,就会一直忙着调度,这是时钟源的中断推着它进行的。我们因此可以说操作系统就是躺在中断中运行的。与此同时,OS也会自己去fork一些进程,这是内核固定进程,会定期去检查OS运行状态,定期把内核缓冲区数据进行刷新、检查闹钟等操作。 

②时间片

时钟中断是固定时间的,假设为1ns。进程的调度都设置了时间片,轮询着调度以尽量保持公平。OS要实现时间片,只需设置int count,当count == 1000(1微秒),每次时钟源中断触发进程调度都会让count--,count减到0后直接切换进程。

时间片就是在主频下的计数器,是以时钟中断为基础构建的。

(3)异常处理

我们已经知道,程序的崩溃就是靠信号终止的。

其中野指针触发段错误,操作系统直接用11号信号杀掉进程,我们捕捉信号后发现OS一直在触发信号。

同理,a / 0也会崩溃,会触发13号信号SIGFPE终止进程。

为什么OS知道我们的进程的内部出错了,为什么OS会一直触发信号?

以a / 0为例,CPU中有寄存器,a -> eax,0 -> ebx, 计算结果 -> ecx。同时还有个状态寄存器Eflags,有溢出标记位,默认为0,保证会把结果正常返回。但当溢出标记位为1,OS就知道CPU硬件内部出错了,OS找到对应的进程后就要用信号杀掉损坏CPU的进程。

当我们捕获信号之后,我们的进程没有退出,直到时间片到了,进行进程切换时会OS会保存寄存器数据,以便下次调用恢复。其中Eflags的标记位也被保存了,OS不会修改它。由此以来,每当调度到这个进程时,CPU都会显示异常,OS会一直尝试杀我们的进程,这导致了死循环调用信号处理。

同理,OS怎么判断野指针呢?CR3寄存器保存页表起始地址,虚拟 -> 物理地址的转换是MMU内存管理单元操作的,它集成在CPU中。当访问野指针(虚拟地址)时,MMU转换去读0,发现无法访问,于是触发了硬件错误,OS知道后发送信号尝试杀掉进程。当后续再轮换调用时,MMU的错误被完整地继承了下来,所以OS会循环发送信号。

(4)软中断

①软中断和硬件中断

上述都是外部硬件中断,需要硬件设备触发。有没有仅靠软件进行中断的呢?

为了让OS支持系统调用,CPU专门设计了对应的汇编指令(int或者syscall),在没有外设下,可以让CPU内部触发中断逻辑。这些汇编指令就可以写在软件中,通过汇编指令 + 中断号推动CPU执行中断向量表方法,这就叫软中断。硬件中断和软中断仅仅是触发方式变为汇编调用,其余流程一致,这很好理解。

两种触发方式最终都是利用中断号调用中断向量表中的函数。例如,int N 指令会触发中断号为 N 的软中断,操作系统会根据该中断号来找到对应的处理函数(范围从 0x00 到 0xFF(即从 0 到 255))

②系统调用表

系统调用也是通过中断完成的。OS系统调用都在系统调用表,集中管理,是由“下标”调用的。系统调用表特别底层且固定,用户无法查看这个表的存在。这个表中各个函数的下标叫系统调用号,在中断向量表中设置一个系统调用的入口函数,用系统调用号调用。

要调用系统调用,就要想办法软中断,int 0x080就是软中断到执行系统调用入口函数,进入固定例程。系统调用号会提前写到寄存器中,可以直接被获取。

系统调用的过程:先把要调用的系统调用号用寄存器存起来,再触发软中断陷入内核,OS根据中断向量表开始进入中断服务,根据寄存器里的系统调用号自动查系统调用表,执行对应方法。

OS提供的系统调用接口根本不是C函数,而是系统调用号 + 约定传递的参数,通过触发软中断、进行中断服务调用的方式实现系统调用功能的。系统调用的真正的底层实际上是汇编。

GNU、glibc给系统进行C语言封装,给我们提供C语言的系统调用。所以我们用的所有系统调用都是C的,是它对该平台的系统调用进行了统一的上层封装,这也是C具有跨平台性的本质。C语言的上层封装还保证了我们系统调用的安全性,不会导致对系统造成伤害。

③缺页中断

缺页异常意思就是有虚拟地址,但物理内存没有申请(分批加载)。当OS需要用到相应空间,但发现还没有物理内存时,就会触发中断,申请并加载物理内存。

④异常、陷阱

OS就是躺在中断例程上的代码块,几乎所有操作都会转为中断。缺页中断、内存碎片处理、除零、野指针错误都是转为软中断,OS会设置中断号走中断例程。异常、陷阱都会转为软中断来处理。

如果发生了软中断且不是因为出错,就是单纯为了陷入中断(系统调用),这叫做陷阱。

而像除零、野指针这种触发错误导致软中断的叫做异常。

OS会根据不同错误或者陷阱由中断号进行调用。

(5)用户态和内核态(重点)

①用户区、内核区

在32位操作系统下,进程的地址空间划分了4G,其中这块虚拟的地址空间包含了我们已知的堆栈段、代码段、数据段、以及命令行参数列表等。所有的这一切所在的内存区域都属于用户区。用户区从0G ~ 3G,共3G的大小。

3G ~ 4G这块叫做内核区,这块内核区也是虚拟的,它拥有共同的内核页表,同用户页表一样,都是映射到物理内存中的。不过需要注意的是,不同进程的内核区都会映射到同一块物理内存。

这里需要注意的是,用户页表每个进程一份,因为虚拟地址和物理地址都要根据不同进程实际情况映射。;而内核页表则是整个系统一份,无论是虚拟地址还是映射的物理地址都是同一份。对于任何进程来说,无论如何调度,它们都能找到同一个OS,访问同一张中断向量表和系统调用表。

无论调用任何函数(库、系统调用),都是在我们自己用户区进行调用的(代码段在用户区)。而被调用的系统调用方法的执行是在内核区进行的。

本质上说,内核区映射到同一块空间是因为OS只有一个,那么如果使得进程映射多块空间,就相当于启动了两个系统,这就是内核虚拟机的思路,当然还有用户虚拟机,这里提一句。

②用户态和内核态之间的切换

前面我们已经知道用户区和内核区了,这两个区域只能被具有对应的身份的人访问,标记身份的就是用户态和内核态。

如果我们要进入内核区,我们需要将我们的身份进行改变,即用户态 -> 内核态;同理,如果要访问用户区,我们也应该将内核态 -> 用户态。 

标记用户态和内核态的是CPU的CS段寄存器。它有两个bit位的标志(CPL):00表示内核,11表示用户。修改用户内核态的本质就是修改标志位。我们都知道MMU是集成在CPU内部,负责进行虚拟地址 -> 物理地址的,只要CPL不允许访问,MMU也自然不会给我们转换地址,我们也自然访问不了对应的空间。用户态和内核态的权限管理是硬件层面的。

当我们在用户区调用系统调用时,会使用int (中断号) 和 syscall (中断号) 触发软中断,进到中断向量表里面去执行系统调用入口函数,进而访问系统调用表,执行系统调用方法,最后回到调用处继续执行代码。在整个过程中,当触发软中断时就会第一次切换状态,将权限标志位CPL改为0,进入内核态。执行完后返回调用处又会切换一次,CPL改为3,进入用户态。

③函数跳转

在上述流程中,我们会有疑问:函数是如何跳转的,跳转回来时如何找到最开始的地址的?A函数调用B,A会把调用B的下一个地址先入栈,后面出栈后就能够找到下一句地址。由此以来就能正确地在内核区和用户区之间进行跳转。汇编层面所有操作都是基于寄存器、地址的。

(6)捕捉信号流程

有了前面知识的积累,我们能够更底层地理解信号捕捉的流程了。

①用户态和内核态的切换

如果来了一个信号,有可能当前进程正在做更重要的事,我们要把信号保存到pending表中。当进程从内核态切换回用户态的时候,进程就会进行信号检查do_signal(),检测当前的pending和block表决定是否处理信号。

当要处理信号时,会根据不同处理信号的方式决定走向。如果是DFL和IGN的情况,那么进程会不急着返回用户态,会在内核态把方法执行完成后再返回(DFL和IGN的代码都在内核区);如果我们自定义捕捉了信号,这些代码都在用户区保存,所以我们要切换回用户态执行处理代码。处理之后,会回到内核态,执行sys_sigreturn()返回主程序,回到用户态。

②对状态切换的理解

为什么执行自定义函数时要做权限切换?直接用内核态执行不行吗?自定义函数存在用户区,需要用户态,而内核态权限更高,切换回用户态是为了避免安全风险,防止内核态被利用。同时内核态进入用户态后执行自定义函数,意味着用户态的操作后果自负!

③对执行流概念的深化

我们执行完自定义函数后,想要回到主程序。为什么不直接回去,反而还要进入内核态呢?实际上自定义函数和主程序没有任何关系,在程序中不存在任何调用关系,信号处理和主程序是两个完全不同的执行流,因此只能先返回到内核。当触发硬件中断,OS会保护现场,存储各个寄存器的状态。其中pc寄存器就保存下一条指令的地址,在这里就是主执行流的下一条指令的地址。因此回到用户态,需要在内核态调用sys_sigreturn()函数,恢复上下文,才可以回到初始时的在主程序执行流。

到这里,我们也能彻底理解信号处理没有新开一个进程,主执行流和信号捕捉执行流,信号捕捉执行流没有在主执行流中被调用,而只是一个主执行流中的分支,进程调用过程中两个分支不会冲突。

下面是执行流切换的过程,仔细体会

(7)volatile

①可重入函数

若一个函数被两个以上执行流同时进入,就有可能遇到下面这种情况,这是单执行流的情况下遇不到的。


因此实例的insert函数是不可重入函数。相对的,还有可重入函数,也就是可以被被两个以上执行流同时进入同时不发生错误的函数。怎么判断呢?

只要使用了全局资源的,new了空间的,基本都是不可重入的,使用的都是局部变量的就可能是可重入的。基本上STL都不可重入,大部分函数也都不可重入。但也有专门设计的系统接口带_r,表示可重入。

②volatile、编译器优化

gcc有优化选项 -O0基础优化,-O1,-O2,-O3优化级别依次增加。

对于主程序执行流和信号处理执行流来说,由于它们从语法上没有任何联系,但实际上可以通过全局资源联系,编译时就有可能被优化出bug。

若在主执行流中对一个全局变量没有修改,而实际上这个全局变量在信号捕捉执行流中被处理。对于高优化的编译器来说,这个全局变量在信号捕捉执行流中的处理无效。我们要从底层来理解优化。

当编译器优化很大时,一些主执行流没有修改的变量会变成寄存器变量,这个变量永远无法被修改。当我们使用这个变量来进行判断时,逻辑判断会直接用寄存器里面的值进行判断而不会使用内存的数据,这就导致信号捕捉执行流中修改变量不会生效,寄存器 + 优化屏蔽了内存的可见性。

如果担心被优化导致出现bug,我们可以使用volatile关键字修饰全局变量,volatitl int flag = 0;就不会被寄存器屏蔽了,这个关键字相当于告诉编译器不要对该变量进行任何优化,以保持内存可见性。

4.信号拓展

(1)SIGCHLD

父进程一般关心子进程什么时候死,这样好回收,以免出现孤儿或者僵尸。事实上,子进程退出时都会向父进程发送SIGCHLD信号,告诉父进程自己结束了。不过默认情况下SIGCHLD的Action是Ign(忽略)。我们可以手动捕获这个信号,当父进程收到信号时再去wait,这样就能实现父子进程异步执行,而不是让父进程一直阻塞在原地。

但是有个问题,即信号处理过程中最多允许再接收一个信号,后续的没意义(pending已经为1了),所以每次需要waitpid + WNOHANG循环,用返回值来判断是没等完还是等完了。

仅Linux下,signal(SIGCHLD, SIG_IGN)处理后,这样fork出来的子进程在终止时会自动清理掉,没有僵尸,不过父进程也得不到status。这里可认为是Linux的特殊处理,仅仅用来处理僵尸的情况。

(2)SIGALRM

alarm(seconds)函数可以设置一个一次性闹钟信号(只会响一次,重复使用需要多次调用),闹钟时间到了之后会发送一个14号SIGALRM信号,默认就是Term终止。我们可以捕获它,利用alarm写一个统计服务器1s执行某种操作多少次的代码,可以用alarm来对比IO对效率的影响有多大等操作。

alarm(0)取消闹钟,其返回值是闹钟剩余时间。如果闹钟自己响了,那返回值就是0。

【Linux】进程信号详解 介绍了信号的种类、属性、信号的产生、信号在内核中的存储形式、信号的捕捉、信号的处理流程等 阅读详情

相关推荐

WebUI自动化测试框架搭建(python+pytest+selenium+allure)

将鼠标移动到要定位的元素上面>右键>点击“检查”>在元素代码上右键>复制>复制XPath。

m0_63729339的博客 1281

Linux 进程信号(超详细的都在这里了,从多个方面【信号的产生(系统闹钟)-信号的保存(sigset_t)-信号的捕捉-基于信号操作系统的运行-可重入函数-Volatile-SIGCHLD信号】讲解

在操作系统中,信号的软件条件指的是由软件内部状态或特定软件操作触发的信号产⽣机制。这些条件包括但不限于定时器超时(如alarm函数设定的时间到达)、软件异常(如向已关闭的管道写数据产⽣的SIGPIPE信号)等。当这些软件条件满⾜时,操作系统会向相关进程发送相应的信号,以通知进程进⾏相应的处理。简⽽⾔之,软件条件是因操作系统内部或外部软件操作⽽触发的信号产⽣。系统闹钟,其实本质是OS必须⾃⾝具有定时功能,并能让⽤⼾设置这种定时功能,才可能实现闹钟这样的技术。定时闹钟也要被管理的:先描述,再组织。

m0_73523775的博客 4353

AFSim 2.9中文手册实战指南:从安装到高级功能详解(附B站视频链接)

本文详细介绍了AFSim 2.9的安装配置、基础功能操作和高级功能应用,帮助用户快速掌握这款强大的仿真平台。从系统要求检查到多体动力学仿真,再到性能优化技巧,全面解析AFSim 2.9的使用方法,适合初学者和进阶用户参考。

weixin_30892037的博客 565

系统级基础信号知识【Linux】【信号产生,捕捉,原理】

操作系统中的信号是一种在进程间传递信息和通知的机制。它可以用来通知进程发生了某种事件,比如用户按下了某个键盘按键、进程收到了某个信号或者发生了某个错误等。手机收到新短信或来电时会发出提示音,这就是一种信号,通知用户有新的事件发生。交通信号灯会发出红、黄、绿三种不同的信号,指示车辆和行人何时可以通行。火灾报警器发出警报声,通知人们有火灾发生,需要立即疏散。门铃响起,通知主人有人来访。警报器在发现入侵者时会发出警报声,通知屋主有危险。可选的处理动作有以下三种1. 忽略此信号。

菜菜成长为后端开发大佬 2724

【阿里云大模型高级工程师ACP习题集】2.3 优化提示词改善答疑机器人回答质量

【摘要】这是我精心整理出对应的习题集,里面足足有 30 道题目,从基础概念到深度拓展,全方位覆盖章节重点、难点。不管你是想检验自己的学习成果,还是想针对薄弱环节进行强化训练,它都能完美适配!

davidkorhenn的博客 1629

ROS-Industrial :simple_message

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录1. 概述2. 协议(Protocol)3. HEADER解析3.1 MSG_TYPE3.2 COMM_TYPE3.3 REPLY CODE 1. 概述 Simple_Message是ROS-Industrial的一部分,定义了用于与工业机器人控制器通信的简单消息连接协议。另外还包括处理连接受限系统的处理器和管理器类。 2. 协议(Protocol) 简单消息(simplemessage)协议定义了ROS的驱动层和机器人控制器之.

flsxyw的博客 780

操作系统 : Linux进程信号

理解信号的工作原理对于深入掌握Linux系统编程至关重要。信号的处理涉及多个层面:从信号的产生、保存到最终的捕捉与处理,每一步都体现了操作系统对进程管理的精巧设计。本文将系统性地介绍Linux信号机制,涵盖以下核心内容:信号的基本概念:信号是什么?它是如何工作的?信号的产生方式:从终端按键到系统调用,多种触发信号的途径。信号的保存与阻塞:内核如何管理未决信号?信号屏蔽字的作用。信号的捕捉流程:用户态与内核态的切换,信号处理函数的执行机制。高级话题:可重入函数、volatile关键字、SIGCHLD信号的应用

m0_74951730的博客 1246

51单片机也能玩转信号发生器?手把手教你用DAC0832和LM358输出四种标准波形

本文详细介绍了如何使用51单片机和DAC0832芯片搭配LM358运放,自制低成本信号发生器,实现正弦波、矩形波、三角波和锯齿波四种标准波形的输出。从硬件选型、电路设计到编程实现,手把手教你完成这一实用电子项目,总成本不到50元,适合电子爱好者和学生实践。

weixin_30530939的博客 551

Linux信号详解

目录前言一、信号概念1、生活中的信号2、计算机中的信号 3、实现信号捕捉二、产生信号的方式1. 通过终端按键产生信号格外拓展:核心转储(core dump)status 2、调用系统函数向进程发信号3. 由软件条件产生信号 4、硬件异常产生信号三、阻塞信号1、概念 2、内核中的表示3、信号集操作函数3.1用户层函数3.2 系统接口四、信号捕获1、用户态和内核态 2、内核如何捕获进程信号2.1捕获信号过程2.2 sigaction五、函数的重入六、c语言关键字volatile总结哈喽,小伙伴们大家好,本篇文章

weixin_59371851的博客 5072

反激电源及其变压器计算与绕制

本内容以一个宽电压输入 24V3A 输出的 72W 反激电源为例来计算电路的各个参数和器件选型,包含反激变压器的计算与绕制方法。

让你爱上电路设计 1935

《模型轻量化-剪枝蒸馏量化系列》YOLOv5无损剪枝(附源码)

无损剪枝模型到几百kb~

cv君的博客 3万+

【Linux】volatile | SIGCHLD | 多线程概念

创建子进程时,只创建PCB,创建出来的PCB继续指向父进程的地址空间代码区假设有很多函数存在,让不同的PCB执行不同的函数相当于在一个进程内部包含多个执行流,指向同一个进程内的不同代码区域每个PCB都是单独的线程线程在地址空间内运行,所以该线程属于进程。

qq_62939852的博客 2250

基于深度学习的ECG心电信号异常分类:从数据集到Transformer实战

心电图(Electrocardiogram, ECG)是诊断心血管疾病最常用、最无创的工具。随着可穿戴设备的普及,海量的心电数据需要自动、快速且准确地分析。人工智能,尤其是深度学习,在心电信号分类任务中表现出了超越传统规则算法的能力。本文将深入探讨ECG异常分类的技术细节,从心电数据的生理基础,到数据预处理,再到使用1D-CNN、LSTM、以及前沿的Transformer模型进行实战演练。文章末尾提供了完整的代码以及多个国际公开数据集的获取方式。

YOLO 188

Linux 进程信号:内核中信号结构、阻塞信号、捕捉信号

Linux 进程信号:内核中信号结构、阻塞信号、捕捉信号

Han同学 1865

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

linux信号相关概念

信号、信号操作函数

羊羊羊 866

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

【Linux系统编程:信号】产生信号 | 阻塞信号 | 处理信号 | 可重入函数 | volatile | SIGCHLD

通过学习信号可以理解进程与进程的一个相对关系,还能理解操作系统与进程的关系。要注意的是进程间通信中的信号量与这里的信号没有半毛钱关系,就像老婆和老婆饼。掌握 Linux 信号的基本概念掌握信号产生的一般方式理解信号递达和阻塞的概念,原理掌握信号捕捉的一般方式重新了解可重入函数的概念了解竞态条件的情景和处理方式了解SIGCHLD信号, 重新编写信号处理函数的一般处理机制。

DanceBit的博客 1157

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

【linux系统编程】信号——信号保存+信号处理

这是一篇将近3w字的超长文章,是信号三部曲的第二部曲及第三部曲的集合,并且还包含以前没学过信号不能讲的知识这里都进行了补充。首先讲了信号保存,信号是如何保存的。然后讲了信号处理,以前说过信号是在合适的时候被处理,什么合适的时候?进程从内核态返回用户态的时候,那什么是用户态,内核态,进程什么时候去OS中执行代码的,进而将虚拟地址空间在做进一步的阐述。以及有关信号的一些接口和接口的使用,并且还阐述如果同一时间发送同类型的信号OS会做什么处理等等知识,以及可重入函数volatile关键字SIGCHLD信号相关知识

fight_p的博客 2104

【Linux】进程信号

进程信号

VHhhbb的博客 1773

Linux操作系统--阻塞信号、捕捉信号

文章摘要:本文详细介绍了Linux系统中信号处理的相关概念和机制。主要内容包括:1)信号递达与未决状态的区别,阻塞信号和忽略信号的不同;2)信号在内核中的表示方式,包括阻塞标志位、未决标志位和处理函数指针;3)信号集操作函数和信号屏蔽字的设置方法;4)信号捕捉的实现原理和sigaction函数的使用;5)可重入函数的概念及其重要性;6)volatile关键字在信号处理中的作用,防止编译器优化导致的数据不一致问题。文章通过具体示例和函数原型,全面阐述了信号处理机制的关键技术点。

2301_78702440的博客 1107

【linux】进程信号(三)信号的处理,信号的捕捉,sigaction,可重入函数,volatile,SIGCHLD信号

一、浅度理解信号的处理 二、重谈地址空间3 三、理解操作系统 四、深度理解信号的处理 五、信号的捕捉,sigaction 六、可重入函数 七、volatile 八、SIGCHLD信号

重铸自身根基的博客 1281

linux信号的概念

信号产生的方式:无论信号如何产生最终一定是谁发送给进程的?OS!为什么?OS是进程的管理者!

Qianxueban的博客 1131

深入剖析Linux——进程信号

Linux信号深度剖析

终为nullptr 2099

[Linux]信号底层概念与操作

信号是操作系统里进程间通信的一种方式。其本质是传递事件通知,让进程知晓特定情况。信号产生多样,键盘输入触发硬件中断后产生,异常、软件条件达成以及系统调用也能引发。产生后,进程保存信号并通过设置处理函数来应对,利用信号屏蔽字控制处理与否。在底层,涉及内核态与用户态切换,内核空间负责处理流程。信号捕捉处理函数完成具体操作,像SIGCHLD信号用于告知子进程状态改变,处理时还得关注可重入函数及volatile关键字的运用呢。

m0_74207969的博客 1279

【Linux信号】Linux进程信号(下):可重入函数、Volatile关键字、SIGCHLD信号

volatile的字面意思是“易变的”。这个变量可能会在当前代码流之外被修改(例如:由信号处理函数、多线程、或者硬件中断修改)。因此,编译器在编译时严禁对该变量进行任何“假定不变”的优化,每次使用它时必须老老实实地去内存地址中读取。下面我们演示如何使用gcc -S命令来查看开启优化后,有无volatile关键字在生成的真实汇编代码上的具体差异。我们直接通过对比真实的汇编逻辑来看一下volatile是如何“保命”的。// 或者去掉 volatilewhile (!flag);

艾莉丝努力练剑的博客,感谢大家一直以来的对艾莉丝的支持和鼓励,uu们如果对C/C++方向感兴趣的话,可以通过艾莉丝主页的微信名片加艾莉丝的好友,和努力练剑的艾莉丝一起加油! 1136

【Linux 17】进程信号

1. 进程的运行。2. 信号的产生。3.信号的捕捉。4. 信号的阻塞 (保存)

shangguanxiu的博客 2395
上一篇: Linux相关概念和易错知识点(24)(认识信号、信号捕捉)
下一篇: Linux相关概念和易错知识点(26)(命名管道、共享内存)
-SGlow-
博客等级 码龄3年 1513粉丝 118原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值