Linux进程信号的产生、保存、处理

模糊控制——基本原理(附MATLAB程序) 模糊化:使用隶属函数将实际输入转换为模糊集合的隶属度值。规则库:利用“如果-那么”规则将模糊输入映射到模糊输出。推理机制:通过规则的模糊化和模糊集合的合成,生成模糊输出。去模糊化:将模糊输出转换为具体的控制信号,常用的方法包括质心法和最大隶属度法。这些步骤综合起来,实现了模糊控制系统对复杂和不确定系统的有效控制。模糊控制系统通过结合模糊逻辑和规则库来处理复杂系统中的不确定性和模糊性。它的核心在于模糊集合和隶属函数,通过推理机处理模糊规则,并最终通过去模糊化生成具体的控制信号。 阅读详情

一、信号的概念

 信号是一种向目标进程发送消息, 异步通知的一种机制,属于软中断。本质上是用软件来模拟中断行为!

 信号在产生之前,操作系统就已经内置了所有信号的识别和处理方式。(通过宏定义出得数字编号识别信号种类;在内核中存在一张handler表,即信号处理函数表。该表的数组下标对应信号编号,数组中存放的内容指向对应信号的处理方式)

 并且信号产生时,操作系统可能在做更重要的事情,也就意味着信号产生之后不会被立即处理,需要被保存。在Linux中,每一个进程PCB中存在一张位图用来保存信号。位图中比特位的位置表示信号种类,比特位内容表示信号的有无!

 进程是无法得知信号何时来的,也就意味着信号的到来和进程执行是异步的。

 同理,在操作系统中已经提前内置了信号信息。我们通过kill -l查看:

在这里插入图片描述

  • 每个信号都有一个编号和一个宏定义名称,这些宏定义可以在signal.h中找到。其中 1~31为普通信号,43~64为实时信号(不关心),没有32、33号信号!这些信号各自在什么条件下产生,默认的处理动作是什么,在signal(7)中都有详细说明: man 7 signal。

二、信号的产生

 在Linux中,信号的产生方式分为四大类:键盘终端产生、系统调用产生、硬件异常产生、软件条件产生!

2.1 键盘终端产生

1)、终端信号产生过程

 我们在终端输入诸如ctrl c、ctrl z、ctrl\等指令,我们发现可以将进程终止退出,或者暂停。当我们输入这些指令后,对应硬件会向CPU发送光电信号通知CPU。此时CPU会将这些光电信号转化为中断号,在中断向量表中找到对应硬件的读取方法,将硬件数据读取到内存中。

 当操作系统识别到这些特殊数据后,不会将数据拷贝给目标进程。而是转化为向目标进程发送信号,从而将目标进程退出或暂停等行为!

2)、操作系统得知硬件数据就绪手段

 硬件和进程之间通常会伴随着数据拷贝。比如我们在终端输入指令信息,最后是需要将数据拷贝到内存中,然后看情况是否需要拷贝给目标进程的。当我们输入完指令回车确认后,意味着键盘资源就绪,等待操作系统将数据读走。但操作系统如何的知硬件资源就绪??

 操作系统监测硬件资源就绪,有两种方式:

  • ①:操作系统定期轮询检测所有硬件,判断那些硬件数据就绪。但这非常不现实,如何评判设定轮询间隔时间?时间太长,系统整体效率降低;时间太短会导致CPU疯狂进程监测,减少进程调度次数,进而影响程序性能!
  • ②:另一种方式就是硬件就绪后,让硬件主动通知操作系统!

 首先CPU周围会存在很多针脚,这些针脚对应唯一的一个编号,每一个针脚对应一个唯一硬件。当硬件资源就绪之后,硬件会向CPU发送光电信号。此时CPU检测到光电信号后,会将收到的光电信号转化为对应针脚的编号,并将该数字保存到寄存器中,我们也将这些编号称为中断号。

 当OS识别到该寄存器中存在数据时,操作系统就知道存在硬件已经硬件资源就绪了,OS会立马停下手中的所有工作,将对应硬件中的数据加载到CPU中,完成数据的加载。

 为了进一步提高读取硬件数据的效率,操作系统中存在一张函数指针数组,该数组中下标位置对应中断号种类,数组中保存了对应硬件的读取方法!我们将该函数指针数组称为中断向量表,该表会在操作系统初始化时生成!此时操作系统通过中断号即可索引到对应硬件的读取方法,快速将硬件数据读取到内存!!

 当然CPU的针脚是有限的,硬件也不是直接和CPU链接。在CPU和硬件之间通信需要经过主板,而主板存在一定的扩展能力。并且并不是所有的硬件都有发送中断能力!
在这里插入图片描述

3)、 实例:前台进程、后台进程

 下面我们创建一个process.cc源文件,让其死循环输出信息。

#include <iostream>
#include <unistd.h>

int main()
{
    int cnt = 0;
    while(true)
    {
        std::cout << "running ..." << ++cnt << std::endl;
        sleep(1);
    }
    return 0;
}
  1. 我们编译运行后,产生一个前台进程。我们可以在终端输入ctrl c发送2号信号来终止前台进程!

请添加图片描述
 我们在键盘上按下ctrl c后,会产生硬件中断。操作系统会识别到硬件数据就绪,此时操作系统读键盘上的数据,发送给目标进程。前台进程因为收到2号信号,进而引起信号退出!!

  1. 我们也可以通过ctrl z发送20号信号暂停前台进程!但由于前台进程不能被暂停,否则键盘将失效。此时当前被暂停的前台进程后转化为后台进程。shell外壳进程快速从后台切换为前台进程。

 下面我们将前台进程输入重定向到log.txt,死循环打印消息。然后ctrl z发送20号信号,此时前台进程会变为后台进程。具体效果如下:

请添加图片描述

 我们发现ctrl z向目标进程发送20号信号后,前台进程变为后台进程,并且被暂停!

  1. jobs指令可以查看当前系统中的后台进程。
  2. bg 指令+ 后台进程编号可以重新启动后台进程。fg 指令+ 后台进程编号可以将后台进程提到前台,变为前台进程!
  3. 前台进程只能有一个(键盘只有一个),后台进程可以有多个。两者本质区别在于前台进程可以接收用户输入,后台不行。shell进程比较特殊,不会被ctrl c杀掉。并且根据具体情况,Os会自动将shell提到前台或后台!!

4)、验证终端按键是否产生信号

 上述我们通过终端按键让进程产生一系列行为。当ctrl c真的向目标进程发送了2号信号吗?ctrl z真的向目标进程发送了20号信号吗?我们需要进一步验证!

 操作系统提供了一个signal系统调用即可,可以自定义捕捉信号。

 #include <signal.h>
 
 //函数原型如下,signal()第二个参数用于自定义捕捉信号
 typedef void (*sighandler_t)(int);
 sighandler_t signal(int signum, sighandler_t handler);

下面我们以自定义捕捉2号信号,分别通过终端ctrl c和用户主动发送2号信号,对比进程行为!!

【源代码如下】:自定义捕捉2号信号,让进程受到2号信号退出时,打印一段消息!!

#include <iostream>
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>

void handler(int signo)
{
    std::cout << "自定义捕捉信号: " << signo << std::endl;
    exit(0);
}

int main()
{
    std::cout << "pid: " << getpid() << std::endl;
    //自定义捕捉2号信号,signal()会将待捕捉信号种类数字传给handler()
    signal(2, handler);
    int cnt = 0;
    while(true)
    {
        std::cout << "running ..." << ++cnt << std::endl;
        sleep(1);
    }
    return 0;
}

【终端ctrl c效果】:

请添加图片描述

【发送2号信号效果】:
请添加图片描述

  • 我们发现两者行为一直,系统都受到了2号信号。进一步验证终端输入可以发送信号!!

2.2 系统调用产生

1)、实例

 操作系统提供了系统调用接口kill,用来向指定进程发送信号!

 #include <signal.h>
 int kill(pid_t pid, int sig); //发送成功,返回0;否则返回-1

【实例】:进程打印3次消息后,通过系统调用接口发送2号信号

#include <iostream>
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>

void handler(int signo)
{
    std::cout << "自定义捕捉信号: " << signo << std::endl;
    exit(0);
}

int main()
{
    int count = 3, cnt = 0;
    signal(2, handler);//自定义捕捉2号信号
    while(true)
    {
        std::cout << "running ..." << ++cnt << std::endl;
        if(--count == 0)
            kill(getpid(), 2);
        sleep(1);
    }
    return 0;
}

【运行结果】:
请添加图片描述

2)、产生信号的系统调用总结

  • ①:kill函数可以给一个指定的进程发送指定的信号。(kill命令是调用kill函数实现的)int kill(pid_t pid, int sig)
  • ②:raise函数可以给当前进程发送指定的信号(自己给自己发信号)。int raise(int signo); //成功返回0,错误返回-1。
  • ③:abort函数异常终止当前进程,并且产生一个SIGABRT信号。这个函数通常用于程序遇到无法恢复的错误时,立即终止程序运行。void abort(void); //就像exit函数一样,abort函数总是会成功的,所以没有返回值

2.3、硬件异常产生

 下面以浮点数溢出和空指针解非法解引用错误为例

1)、浮点数溢出,CPU产生信号

 我们知道除式中,除数为0是非法的。此时CUP硬件会发送8号信号,表示浮点数异常Floating point exception。我们先来看看相关现象,代码如下:(我们特意让进程一直被运行,并且8号信号自定义捕捉。进程收到8号信号时不退出)

#include <iostream>
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>

void handler(int signo)
{
    std::cout << "自定义捕捉信号: " << signo << std::endl;
    sleep(1);
}

int main()
{
    std::cout << "pid: " << getpid() << std::endl;
    signal(8, handler);

    int x = 10;
    x /= 0;
    while(true)
    {}
    return 0;
}

【运行结果】:

请添加图片描述
 我们观察到进程确实收到了8号信号。

2)、浮点数溢出,产生信号原理

 在CPU中存在许多寄存器,其中存在一个名为status的状态寄存器,其中存在一个标记位用来保存最近一次运算结果是否发送溢出!!一旦发送浮点数溢出,该标志位会被置为1,此时结果无意义!

 对于上述代码,假设我们CPU寄存器eax中保存10,ebx寄存器中保存0。10/0,本质上是除一个无限小的数,导致结果无限大,发生溢出。此时操作系统会将溢出标记位由0置1,此时操作系统会识别到该信息,会立即暂停进程。此时操作系统会将该异常解释为kill(targetprocess, signo)。然后将相关信号保存到进程PCB的信号位图中中!当异常处理完后,下次会被CPU再次调度运行。但在进程调度前,进程上下文需要先被恢复,此时状态寄存器中的溢出标记位以及为1,此时操作系统会再次发送相关信号,进入死循环。
在这里插入图片描述

3)、空指针解引用错误,MMU产生信号原理

 MMU(内存管理单元),它是一种负责处理中央处理器(CPU)的内存访问请求的计算机硬件,现如今一般别集成到CPU上。 它的功能包括虚拟地址到物理地址的转换(即虚拟内存管理)、内存保护等!

 对空指针进行非法解引用,即试图对0号地址进行写入。但此时页表中没有建立相关映射,此时MMU进程虚拟地址向物理地址转化时发送失败,MMU报错,相关标志位改变。该变化会被OS识别后向目标进程写信号!!

2.4 软件异常产生信号

 对于管道,比如匿名管道等存在同步机制的管道。当读端关闭,此时管道写端也会关闭退出。这就是一种典型的软件异常。当管道写端关闭,写端进行写入时会触发 SIGPIPE14信号。进而关闭读端退出!

 下面我i们以alarm函数为例,测试软件异常。
 调用alarm函数可以设定一个闹钟,也就是告诉内核在seconds秒之后给当前进程发SIGALRM信号, 该信号的默认处理动作是终止当前进程。

#include <unistd.h>
unsigned int alarm(unsigned int seconds);//返回值是0或者是以前设定的闹钟时间还余下的秒数
// alarm(0):表示取消原有闹钟,并返回上一个闹钟的剩余时间

 下面我们设置一个3秒的闹钟,程序运行后向进程发送14号信号!

#include <iostream>
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>

int cnt = 0;

void handler(int signo)
{
	//下面注释代码:我们可以主动发送14号信号,历史闹钟剩余时间,并取消历史闹钟
    //int n = alarm(0);//取消历史闹钟,如果存在返回剩余时间
    // int n = alarm(3); //从设闹钟,返回上一个闹钟剩余时间
    //std::cout << "result:" << n << std::endl;
    
    std::cout << "自定义捕捉信号: " << signo << "alarm" << std::endl;
    exit(0);
}

int main()
{
    std::cout << "pid: " << getpid() << std::endl;
    signal(14, handler);
    alarm(30);

    while (true)
    {
        sleep(1);
    }
    return 0;
}

【运行结果】:
请添加图片描述

三、Core Dump核心转储

 Core Dump核心转储是指在进程异常终止时发送信号,如果信号的默认处理方法为core,此时操作系统会将该进程退出的核心上下文转储到磁盘上,形成core文件。该文件中包含调试信息,文件较大,并且可能包含用户密码等敏感信息,一般默认禁止生成。
 在LInux中绝大部分信号的默认行为都是终止进程,并且分为Term、Core两大类。其中Term报错进程终止原因非常明确,比如管道破损读端关闭导致进程终止。而Core类报错更像一种真正的异常,虽然问题原因瞄准准确,但问题一般比较严重,通常是程序代码本身存在问题,并且需要用户对代码进一步排查。
在这里插入图片描述
 所以在发送Core时,除了终止程序,还会生成一个Core文件。Core文件会将当前进程退出的核心上下文进行保存,转储到磁盘上。可以通过ulimit -a查看系统配置信息,其中就包含core文件的默认大小.(默认为0).但我们可以用ulimit -c命令改变Shell进程的Resource Limit,允许core文件最大为1024K: ulimit -c1024
在这里插入图片描述

四、信号保存和信号集

4.1 信号相关术语概念

  1. ①:执行信号的处理动作称为信号递达(Delivery)
  2. ②:信号从产生到递达之间的状态称为信号未决(Pending)。即信号产生后未被立即处理,保存在信号位图中。
  3. ③:进程可以阻塞信号。被阻塞的信号会始终保持未决状态,只有解除阻塞后才能被递达!
  4. ④:阻塞和忽略不同。忽略本身是处理信号的一种方式;而阻塞的信号没有没处理,处于未决状态。

4.2 信号内核保存方式

 在进程PCB中,存在3张表:block表、pending表和handler表(1~31号信号保存方式)。具体如下:

在这里插入图片描述

  1. 每个信号都存在两个标志位(阻塞和pending),以及一个函数指针表示信号的处理动作。
  2. 在信号产生后,操作系统会将Pending表中特定比特位内容置1。如何需要将该信号设置为阻塞状态,此时仅需将block位图中的特定比特位下标由0置1即可。
  3. handler表中保存的是信号处理函数指针。信号处理方式由3种:默认、忽略和自定义。默认和忽略分别对应宏SIG_DFL、SIG_IGN,这两个宏是由数字0和1强壮为的函数指针。在这里插入图片描述
  4. 操作系统在处理信号时,首先会检查Pending是否存在信号,即位图中是否存在比特位为1。如果存在,此时OS会查看block表中查看信号是否设置位阻塞。如果信号没有阻塞,此时OS会根据信号编号索引到handler表中,执行对应的信号处理方法!
  5. 在Linux中,:规信号在递达之前产生多次只计一次。而实时信号在递达之前产生多次可以依次放在一个队列里。
  6. 上述xxx位图只是站在内核的角度表述。在用户层,我们一般将block位图表称为阻塞信号集或信号屏蔽字;而将Pending位图称为未决信号集!

4.3 信号集操作函数

 对于信号的处理方法,我们直接通过系统调用signal函数即可将自定义方法设进至内核。但信号屏蔽字和未决信号集是位图结构,如果也让用户自定义设置不仅繁琐,而且非常容易出差。
 所以操作系统提高了一个新的数据结构sigset_t(称为信号集),这个类型可以表示每个信号的“有效”或“无效”状态,在阻塞信号集中“有效”和“无效”的含义是该信号是否被阻塞,而在未决信号集中“有效”和“无效”的含义是该信号是否处于未决状态。

1)、信号集操作函数

 系统中提高了5个信号集操作函数:

#include <signal.h>
int sigemptyset(sigset_t *set); // 将信号集清空,比特位全0
int sigfillset(sigset_t *set);  // 将信号集比特位全部置1
int sigaddset (sigset_t *set, int signo); // 将指定信号添加到信号集中
int sigdelset(sigset_t *set, int signo); // 从信号集中删除指定信号
int sigismember(const sigset_t *set, int signo); // 判断信号集中是否存在指定信号

2)、sigprocmask

 调用函数sigprocmask可以读取或更改进程的信号屏蔽字(阻塞信号集)。

#include <signal.h>
int sigprocmask(int how, const sigset_t *set, sigset_t *oset); 
返回值:若成功则为0,若出错则为-1
  • ①:sigprocmask函数可以将信号机通过参数set传入设置进内核,并将老的信号屏蔽字通过oset带出。
  • ②:how参数选项有如下3种:

|将set中包含的信号设置进当前信号屏蔽字,相当于
-------- | -----
电脑  | $1600
手机  | $12

3)、sigpending

#include <signal.h>
sigpending
读取当前进程的未决信号集,通过set参数传出。调用成功则返回0,出错则返回-1。

五、信号捕捉处理

 进程从内核态返回用户态时发生信号捕捉!!

5.1 用户态、内核态

 用户态是一种受控状态,能够访问的资源是有限的。而内核态是一种操作系统的工作状态,能够访问绝大部分系统资源!!(系统调用的背后就包含身份的变化)

5.2 如何标识用户态和内核态

 进程是被加载到CPU上运行的,而CPU本身就存在工作级别。在PCU中存在一个名为CS的寄存器。该寄存器中的后两个比特位的内容表示CPU的工作级别。(1表示内核态,3表示用户态)
 所以进程运行时,只需要检测CS寄存器的后两个比特位的内容即可判断进程当前所处工作状态!

 除此之外,CPU中还存在两个寄存器CR3和CR1。R3寄存器中保存的是页目录表的物理地址,帮助快速找到页表地址!而CR1寄存器保存了曾经引发缺页中断的虚拟地址。

5.3 操作系统如何被运行?

 首先进程间是相互独立的,因此每个进程都存在一张用户级页表。此处在外,还存在一张内核级页表。;所有进程共用同一张内核级页表,该页表指向的是操作系统的代码和数据!!除此在外,还存在一个名为CMOS的硬件单元,该硬件会周期性的,高频率的向CPU发生时钟中断。当CPU收到对于的中断信号时,CPU会通过当前进程的CPB找到内核级页表,进而找到操作系统的代码和数据进行执行!!

5.4 sigaction

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

struct sigaction {
    void     (*sa_handler)(int);
    void     (*sa_sigaction)(int, siginfo_t *, void *);
    sigset_t   sa_mask;
    int        sa_flags;
    void     (*sa_restorer)(void);
};
  1. sigaction函数可以读取和修改与指定信号相关联的处理动作。调用成功则返回0,出错则返回- 1。signo
    是指定信号的编号。若act指针非空,则根据act修改该信号的处理动作。若oact指针非 空,则通过oact传
    出该信号原来的处理动作。act和oact指向sigaction结构体。
  2. 将sa_handler赋值为常数SIG_IGN传给sigaction表示忽略信号,赋值为常数SIG_DFL表示执行系统默认动
    作,赋值为一个函数指针表示用自定义函数捕捉信号,或者说向内核注册了一个信号处理函 数,该函数返回
    值为void,可以带一个int参数,通过参数可以得知当前信号的编号,这样就可以用同一个函数处理多种信
    号。显然,这也是一个回调函数,不是被main函数调用,而是被系统所调用。

5.5 信号的捕捉流程

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

  1. 在函数栈帧开辟时,就以及内置有关函数结束后返回值放回位置信息。此时OS只需在创建用户自定义方法时,串改该函数的返回值,改为sigreturn的地址即可!
  2. 信号捕捉处理是在所有信号都以及处理完成之后,才会返回用户态!
  3. 我们不一定通过系统调用陷入内核,执行完,返回用户态才进行信号检查。一个进程在生命周期中会涉及到进程切换。但进程重新被加载运行时,OS需要先进行内核态将当前进程的数据进行恢复。恢复完成之后,OS需要将进程的工作模式从内核态切换会用户态。在该过程中,OS会对进程信号进行自定义捕捉,对信号进程处理!

六、可重入函数

6.1 不可重入函数实例

 先来解释下面这段流程图函数。首先mian函数正在执行链表List的头插。但不巧的时,新节点在插入一般时(即只执行性node1->next=head->next, 但还未执行head->next=node1),由于进程时间片已经到了,需要却换到下一个进程。

 在上述过程中,未决信号集中已经保存了一个信号。该信号的处理当时为自定义捕捉insert。(该信号的捕捉方式是向链表List中头插节点)

 当下一次该进程被重新调度时,OS在内核态工作模式将当前进程的数据和硬件上下文恢复之后,需要返回用户态执行剩下代码。在返回用户态之前,信号监测,执行insert函数完成头插node2节点。当返回用户态时,执行头插node1节点的下一步。

 此时我们发现头节点head指向node1,而node2失效导致问题产生!在这里插入图片描述

6.2 可重入函数、不可重入函数

 可重入函数是指一个函数被多个执行流进入,但程序本身或程序逻辑不会出现任何异常时,我们称该函数为可重入函数!

 像上例这样,insert函数被不同的控制流程调用,有可能在第一次调用还没返回时就再次进入该函数,这称为重入,insert函数访问一个全局链表,有可能因为重入而造成错乱,像这样的函数称为 不可重入函数,反之,如果一个函数只访问自己的局部变量或参数,则称为可重入(Reentrant) 函数!

 如果一个函数符合以下条件之一则是不可重入的:

  1. 调用了malloc或free,因为malloc也是用全局链表来管理堆的.
  2. 调用了标准I/O库函数。标准I/O库的很多实现都以不可重入的方式使用全局数据结构.
  3. 使用全局或静态变量,或未加保护的共享资源!

七、volatile关键字

 保持内存的可见性。告诉编译器,被volatile修饰的变量,不允许被优化。对该变量的任何处理操作,都必须在真实的内存中进行操作!

#include <stdio.h>
#include <signal.h>
int flag = 0;
void handler(int sig)
{
 printf("chage flag 0 to 1\n");
 flag = 1;
}
int main()
{
 signal(2, handler);
 while(!flag);
 printf("process quit normal\n");
 return 0;
}
[hb@localhost code_test]$ cat Makefile 
sig:sig.c
 gcc -o sig sig.c -O2 // -O2表示编译器优化等级
.PHONY:clean
clean:
 rm -f sig
[hb@localhost code_test]$ ./sig 
^Cchage flag 0 to 1
^Cchage flag 0 to 1
^Cchage flag 0 to 1

八、SIGCHLD信号

 为了防止子进程退出时进入僵尸状态,导致内存泄漏问题,父进程通常需要通过wait/waitpid来等待回收子进程。但子进程退出时并不是静悄悄的,而是会像父进程发生SIGCHLD信号!但SIGCHLD信号的默认处理动作是忽略!

 所以这里还有一种新的回收子进程方式。父进程直接自定义捕捉SIGCHLD信号,在自定义函数中对子进程进行回收。(一旦调用了自定义函数,意味着父进程信号未决图中一定保存了SIGCHLD信号,一定有子进程退出了)

事实上,由于UNIX 的历史原因,要想不产生僵尸进程还有另外一种办法:父进程调 用sigaction将SIGCHLD的处理动作置为SIG_IGN,这样fork出来的子进程在终止时会自动清理掉,不 会产生僵尸进程,也不会通知父进程。系统默认的忽略动作和用户用sigaction函数自定义的忽略 通常是没有区别的,但这是一个特例。此方法对于Linux可用,但不保证在其它UNIX系统上都可用!

Open3D 高斯牛顿法优化的ICP点云配准 本文介绍了基于高斯牛顿法的ICP点云配准算法。算法通过最小化源点云与目标点云之间的误差函数,求解最优的刚性变换参数(平移向量和欧拉角)。核心内容包括:1)建立误差函数和目标函数;2)推导雅可比矩阵计算,特别是旋转导数的李代数近似;3)详细阐述高斯牛顿法的迭代流程,包括变换计算、最近邻搜索、参数更新等步骤;4)分析算法的优缺点,指出其具有二阶收敛速度但可能陷入局部最优。最后给出了完整的数学推导过程,包括误差函数的泰勒展开和目标函数的近似优化。该算法适用于三维点云配准任务,但需要良好的初始位姿以避免局部收敛问题 阅读详情

相关推荐

【hadoop编译报错】(yarn install) on project hadoop-yarn-applications-catalog-webapp Failed to run task

ambari+bigtop自定义组件集成

TTBIGDATA的博客 1803

操作系统 —— 信号

操作系统的种种细节,有这理解,还怕面试问到吗?

lyzzs222的博客 1461

Mac用户福音:三步搞定PyMol开源版,告别许可证弹窗(附Homebrew/MacPorts安装指南)

本文为Mac用户提供三步安装PyMol开源版的详细指南,帮助科研人员告别许可证弹窗烦恼。通过Homebrew或MacPorts包管理器安装开源核心,并与商业版图形界面整合,实现无干扰的分子可视化研究体验。特别适合MacOS用户快速部署PyMol进行结构生物学分析。

weixin_28743405的博客 194

【LINUX】进程信号时间线描述(产生-判断过程-处理)

进程信号(产生-存储-处理)背景知识信号产生通过终端按键产生信号Core Dump调用系统函数向进程发信号由软件条件产生信号由硬件异常产生信号总结信号判断过程阻塞信号信号其他相关常见概念在内核中的表示sigset_t信号处理信号集操作函数捕捉信号内核如何实现信号的捕捉sigaction 背景知识 信号是进程之间事件异步通知的一种方式。 用kill -l可以查看信号列表 每个信号都有一个编号和一个宏定义名称,这些宏定义可以在signal.h中找到,例如其中有定 义 #define SIGINT 2 编号

Anton的博客 1279

浙政钉(专有钉钉)门户免登(超详细)

钉钉家族 介绍浙政钉门户免登之前,首先搞清楚几个软件的关系,软件分别是:钉钉,专有钉钉,浙政钉 钉钉 是阿里巴巴集团专为中小企业打造的沟通和协同的多端平台。 专有钉钉 原名 政务钉钉,有更开放的设计能力、集成能力、更结构化协同产品、更定制化开发平台。支持专有化部署,数据落本地,更安全、客户可对该产品持牌运营、结构化编排,协助构建本地应用中心、提供移动应用全面安全保障体系。 浙政钉 为规范浙政钉整体架构体系,按照统分结合原则,由省政府办公厅统一设计整体工作界面和系统框架,统筹指导全省统建应用建设,各单

一缕南风的博客 2万+

飞秒激光加工石英玻璃的COMSOL多物理场仿真研究

多物理场仿真是现代工程研发的重要工具,通过耦合电磁、热传导和流体力学等物理场,可以准确预测复杂工况下的材料行为。COMSOL Multiphysics作为主流仿真平台,其双温模型能精确描述飞秒激光加工中的电子-声子耦合过程。这种仿真技术可显著降低实验成本,在微纳加工领域尤为关键。针对石英玻璃这类光学材料,仿真能有效优化激光参数,实现亚微米级精度的冷加工。研究显示,结合移动网格技术和自定义材料状态函数,可以准确预测烧蚀形貌与热影响区分布,为光学器件和微流控芯片制造提供可靠工艺指导。

weixin_29290863的博客 240

操作系统:信号

文章目录一、信号概念1、个人理解2、信号/事件 产生方式3、信号处理方式二、、早期信号1、不可靠信号2、可靠信号定义3、被中断的系统调用 一、信号概念 1、个人理解        信号究竟是什么?追溯到计算机软件源头,“信号”这个词汇从何而来? 尽管经验有限,但是笔者还是尝试表述下自己对信号的一些认识;   ...

uncle103的博客 3193

【EB-03】 AUTOSAR builder与EB RTE集成

打开EB工具后,在EB的步骤是:执行MultiTask(2)-> Mapping Component to Partitions(4)->Task Mapping(5)-> SvcAs_Trigger(7)-> Code Generation(8)如涉及新增BSW Module,也需要重复以上步骤。

libuping2023的博客 960

Linux环境编程 day04 中断、信号、计时器

Linux环境编程 day04 中断、信号、计时器 一、基本概念 1、中断 暂停当前执行的任务,转而执行其它任务,待完成后再返回继续执行当前任务。 硬件中断:来自硬件设备的中断 软件中断:来自其它程序的中断 2、信号是一种软件中断,信号提供一种异步执行任务的机制。 3、常见的信号 SIGSEGV(11) 段错误信号 试图访问未映射过虚拟内存,或向没有写权限的内存写入数据 终止+core SIGINT(2) 终端中断符信号 用户按中断键(Ctrl+C),产生此信号,并送至前台进程组的所有进程 终止 SIG

no_face_jack的博客 432

【现代人形机器人:从物理建模到大模型驱动的控制与学习】第1章 机器人建模回顾

本章建立读者进行后续控制 / 优化 / 学习工作的数学与计算基础。内容分为三大块:刚体运动学:位姿表示、坐标变换、旋转参数与李代数/李群(指数映射、twist)多关节机构的正/逆运动学:DH 与 POE 两种建模、雅可比矩阵推导、数值/解析逆解方法与奇异性问题约束动力学:拉格朗日公式、牛顿—欧拉递归算法、接触/冲击模型、受约束系统的方程(拉格朗日乘子与互补性条件)每一节同时给出与练习题。假设读者已具备线性代数(矩阵、特征分解、SVD)、多变量微积分与基础力学(牛顿第二定律)知识。

u012133341的博客 182

运行 ui5 serve 命令行报错的处理方法

如果大家运行 ui5 serve 命令行,报如下的错误消息: ui5 不是内部或外部命令,也不是可运行的程序: 只需要执行命令行,全局安装 ui5 cli(command line interface)这个命令行工具即可: npm install --global @ui5/cli 这个 ui5 cli 的入口执行文件,实际安装在了我 Node.js 的安装目录下: 更多Jerry的原创文章,尽在:“汪子熙”: ...

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 1338

PyQt5之信号与槽介绍

PyQt5之信号与槽介绍 PyQt的窗口控件类中有很多内置信号,开发者也可以添加自定义信号。在编写一个类时,要先定义该类的信号与槽,在类中信号与槽连接,实现对象之间的数据传输。信号与槽具有如下特点: 一个信号可以连接多个槽; 一个信号可以连接另一个信号; 信号参数可以是任何Python类型; 一个槽可以监听多个信号; 信号与槽的连接方式可以是同步连接,也可以是异步连接; 信号与槽的连接可能会跨线程; 信号可能会断开。 一、定义信号 为QObject对象创建信号: -使用pyqtSignal()函

qq_44880255的博客 2188

AMBA-CHI协议详解(五)

 每个事务由许多不同的packets组成,这些数据包通过互连(interconnect)传输。packets内的一组ID域段用于提供有关包的附加信息。

Crazzy_M的博客 1960

Linux进程信号(预备工作、信号产生、信号保存、信号处理)

完后在进程不会直接由内核态返回用户态,此时进程还处于一个拥有较高权限的状态,操作系统会通过CPU中的寄存器找到进程的PCB,进而对PCB中的三张表(pending位图,block位图,handle函数指针表)进行检测,先遍历block位图,如果为1,说明该信号被忽略,就不到pending中检测了,如果为0,就到pending中查看,pending中如果为1,说明收到该信号了,这时要去handler表中查看匹配的方法。所以处理信号时,如果是执行用户自定义的函数,进程需要先回到用户态,再处理信号,让信号递达。

m0_61832025的博客 1786

Devexpress16.2.6破解工具

Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具Devexpress16.2.6破解工具

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

Linux进程信号(产生、保存、处理)/可重入函数概念/volatile理解/SIGCHLD信号

本篇文章重点详细地写了Linux进程信号的知识点:Linux进程信号的概念、信号产生的方式、信号传递和信号阻塞的原理、信号捕捉的方式、内核态、用户态、可重入函数的概念、volatile理解等等。

wjmhlh的博客 1057

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

Linux进程信号:产生、保存、阻塞与处理

Linux信号是异步事件通知机制,用于告知进程发生了特定事件。信号本质为整数编号,具有默认动作、忽略或自定义处理三种响应方式。其生命周期包括产生、保存(pending)、阻塞检查与处理。信号可由键盘输入(如Ctrl+C)、kill命令、alarm定时器或硬件异常触发。通过block表屏蔽信号,pending表暂存未处理信号,handler表定义处理逻辑。使用sigset_t管理信号集合,结合sigprocmask等接口实现精细控制,确保信号在合适时机被处理。

AbandonForce的博客 242

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

【Linux杂货铺】进程信号

【Linux杂货铺】进程信号 ,本期内容将讲解信号的概念,本文旨在通过粗俗易懂的语言,并配上清晰的图画,让大家更好的理解信号的概念。

jupangMZ的博客 2902

【Linux】进程信号

关于进程信号的相关内容

weixin_69380220的博客 1742

【Linux进程信号(一)】信号概念/产生/保存/处理

LINUX信号

G17861308017的博客 901

<Linux> 进程信号

关于进程信号的概念,分产生、保存、处理三个阶段

weixin_61522065的博客 1354

【Linux】信号

本篇文章全面探讨了信号在操作系统中的作用及其处理机制。首先介绍了信号的基本概念,随后详细阐述了信号的产生方式,包括通过键盘、系统调用(如kill、raise、abort函数)、异常、软件条件(如关闭管道读端、alarm函数)等方式。接着,文章讨论了信号的保存方法,包括信号集sigset_t和相关函数的使用。在信号处理部分,着重介绍了信号捕捉和sigaction函数。最后,文章补充了与信号相关的重要概念,如可重入函数、volatile关键字和SIGCHLD信号的处理。希望本篇文章对大家学习信号有所帮助。

是阿建吖! 2863

Linux 进程信号

提供一个信号处理函数,要求内核在处理该信号时切换到用户态执行这个处理函数)我们在上面写的Ctrl+c实际是给该进程发2号信号。我们接下来写个代码测试一下。我们先认识一个接口。

puppy_1mo的博客 1392

[linux]进程信号(信号的概念,信号的产生方式,信号的相关接口、指令,函数,信号怎么保存(原理),信号怎么处理)

信号是进程之间事件异步通知的一种方式,属于软中断。每个信号只有一个bit的未决标志,非0即1,不记录该信号产生了多少次,阻塞标志也是这样表示的。因此,未决和阻塞标志可以用相同的数据类型sigset_t来存储,sigset_t称为信号集,这个类型可以表示每个信号的“有效”或“无效”状态,在阻塞信号集中“有效”和“无效”的含义是该信号是否被阻塞,而在未决信号集中“有效”和“无效”的含义是该信号是否处于未决状态。

2202_75305885的博客 945

Linux:进程信号

可以设置信号的处理函数、信号的阻塞行为以及信号的属性。handler是信号处理函数的指针,可以是三种情况之一(SIG_DFL(signum默认的信号处理方式)、SIG_IGN(忽略该信号)、自定义函数指针)每个信号在信号集中用一个位来表示,若第n位为1,则表示信号n在信号集中,若为0,则表示不在信号集中。set:指向要修改的新信号集的指针。阻塞和忽略是不同的,阻塞是信号不会被递达,而忽略是在信号递达之后可选的一种处理动作。被阻塞的信号产生时将保持在未决状态,直到进程解除对此信号的阻塞,才执行递达的动作。

2301_80655639的博客 941

【Linux】进程信号(一):信号的产生与信号的保存

【Linux】进程信号(一):信号的产生与信号的保存

tan_run的博客 2589

Linux系统:进程信号

本章将系统地介绍Linux系统中信号的概念,以信号的生命周期为路线,先后学习信号的产生,信号的保存,信号的处理。

yourfriendyo的博客 954
上一篇: Linux文件:EXT2文件系统工作原理 & 软硬链接
下一篇: Linux:进程池制作(匿名管道版本 & 命名管道版本)
小白debug~
小白debug~ 新星创作者: C/C++技术领域 新星创作者: C/C++技术领域
博客等级 码龄4年 3510粉丝 128原创
评论 24
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

打赏作者

小白debug~

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

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

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

打赏作者

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

抵扣说明:

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

余额充值