『Linux从入门到精通』第 ㉖ 期 - 信号概念 & 信号的产生

这篇具有很好参考价值的文章主要介绍了『Linux从入门到精通』第 ㉖ 期 - 信号概念 & 信号的产生。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

『Linux从入门到精通』第 ㉖ 期 - 信号概念 & 信号的产生,Linux从入门到精通,linux,redis,android

💐专栏导读

🌸作者简介:花想云 ,在读本科生一枚,C/C++领域新星创作者,新星计划导师,阿里云专家博主,CSDN内容合伙人…致力于 C/C++、Linux 学习。

🌸专栏简介:本文收录于 Linux从入门到精通,本专栏主要内容为本专栏主要内容为Linux的系统性学习,专为小白打造的文章专栏。

🌸相关专栏推荐:C语言初阶系列C语言进阶系列C++系列数据结构与算法

💐文章导读

本章我们将学习Linux中信号的概念。包括信号的概念、信号的发送以及信号的4中产生方式~

一、🐧什么是信号

1.🐦生活中的信号

在生活中存在各种各样的信号,例如:红绿灯、闹钟、手势……每当我们接收到一个信号,我们就会执行对应的操作,例如红灯停、绿灯行……

为什么我们会对不同的信号有对应的执行动作呢?原因是:

  1. 我们能够识别一个信号,知道其中的含义
  2. 我们从小接受的教育告诉我们应当如何去做

但是我们收到一个信号之后必须去执行相应的动作吗?那也不一定。

  • 假设你在网上买了很多件商品,再等待不同商品快递的到来。但即便快递没有到来,你也知道快递来临时,你该怎么处理快递。也就是你能“识别快递”

  • 当快递员到了你楼下,你也收到快递到来的通知,但是你正在打游戏,需5min之后才能去取快递。那么在在这5min之内,你并没有下去去取快递,但是你是知道有快递到来了。也就是取快递的行为并不是一定要立即执行,可以理解成“在合适的时候去取”。

  • 在收到通知,再到你拿到快递期间,是有一个时间窗口的,在这段时间,你并没有拿到快递,但是你知道有一个快递已经来了。本质上是你“记住了有一个快递要去取”。

  • 当你时间合适,顺利拿到快递之后,就要开始处理快递了。而处理快递一般方式有三种:1. 执行默认动作(幸福的打开快递,使用商品)2. 执行自定义动作(快递是零食,你要送给你你的女朋友)3. 忽略快递(快递拿上来之后,扔掉床头,继续开一把游戏)。

  • 快递到来的整个过程,对你来讲是异步的,你不能准确断定快递员什么时候给你打电话。

2.🐦技术应用中的信号

在Linux中,我们常常通过键盘按下 Ctrl + c 来终止一个前台进程。

用户按下Ctrl + c ,这时键盘会产生一个硬件中断,被OS获取,解释为信号,发送给目标进程,前台进程因为收到这个信号,进而引起进程退出。

$ ./myprocess 
myprocess running..., pid: 27851
myprocess running..., pid: 27851
myprocess running..., pid: 27851
myprocess running..., pid: 27851
myprocess running..., pid: 27851
myprocess running..., pid: 27851
^C
$ 

前台进程与后台进程

  1. ./filename 启动一个进程,该进程为前台进程,在这条命令后加一个 & 可以将该进程放到后台运行;
$ ./filename 	# 启动后,进程在前台运行
$ ./filename & 	# 启动后,进程在后台运行
  1. Shell可以同时运行一个前台进程和任意多个后台进程;
  2. 若有进程在前台运行时,Shell必须等待进程结束才能接受新的指令或启动心得进程;
  3. Ctrl + c 只能发送给前台进程

在许久之前,我们也曾用过 kill -9 的指令来终止一个进程,它的本质也是给进程发送 9 号信号来让进程终止。

『Linux从入门到精通』第 ㉖ 期 - 信号概念 & 信号的产生,Linux从入门到精通,linux,redis,android

3.🐦查看信号列表

在Linux中我们可以使用kill -l 来查看系统定义的信号列表。

$ kill -l
 1) SIGHUP	 2) SIGINT	 3) SIGQUIT	 4) SIGILL	 5) SIGTRAP
 6) SIGABRT	 7) SIGBUS	 8) SIGFPE	 9) SIGKILL	10) SIGUSR1
11) SIGSEGV	12) SIGUSR2	13) SIGPIPE	14) SIGALRM	15) SIGTERM
16) SIGSTKFLT	17) SIGCHLD	18) SIGCONT	19) SIGSTOP	20) SIGTSTP
21) SIGTTIN	22) SIGTTOU	23) SIGURG	24) SIGXCPU	25) SIGXFSZ
26) SIGVTALRM	27) SIGPROF	28) SIGWINCH	29) SIGIO	30) SIGPWR
31) SIGSYS	34) SIGRTMIN	35) SIGRTMIN+1	36) SIGRTMIN+2	37) SIGRTMIN+3
38) SIGRTMIN+4	39) SIGRTMIN+5	40) SIGRTMIN+6	41) SIGRTMIN+7	42) SIGRTMIN+8
43) SIGRTMIN+9	44) SIGRTMIN+10	45) SIGRTMIN+11	46) SIGRTMIN+12	47) SIGRTMIN+13
48) SIGRTMIN+14	49) SIGRTMIN+15	50) SIGRTMAX-14	51) SIGRTMAX-13	52) SIGRTMAX-12
53) SIGRTMAX-11	54) SIGRTMAX-10	55) SIGRTMAX-9	56) SIGRTMAX-8	57) SIGRTMAX-7
58) SIGRTMAX-6	59) SIGRTMAX-5	60) SIGRTMAX-4	61) SIGRTMAX-3	62) SIGRTMAX-2
63) SIGRTMAX-1	64) SIGRTMAX	

我们一眼看去貌似总共有64个信号,但是再仔细一看我们发现这里面是没有 32,33 的信号的,且信号是从1开始编号的。

在Linux系统中,信号的编号范围通常是1到31。这些信号的含义是由POSIX标准定义的,是标准的UNIX信号。然而,32到63之间的信号编号通常被用于扩展,称为实时信号(Real-time signals)。本章我们不讨论实时信号。

每个信号都有一个编号和一个宏定义名称,这些宏定义可以在signal.h中找到。

4.🐦信号的发送

因为信号可能随时产生,所以在信号产生前,进程可能在做优先级更高的事情,当信号来临时,进程可能不能立即处理该信号,而是在往后合适的实际处理。

那么当进程收到信号时,如果它暂时来不及处理这个信号,那么它就必须将这个信号暂时保存起来。也就是一个信号总会经过这三个过程:

  • 信号的产生;
  • 信号的保存;
  • 信号的处理;

那么进程是如何记录接受到的信号的呢?答案是先描述再组织。在进程的task_struct结构体中存在一个位图结构(uint32_t signals)用来管理信号。

比特位的位置对应信号的编号,比特位的内容(0或1)对应是否收到该信号。所以

  • 所谓发送信号,本质是写入信号。直接将指定进程中的信号位图中指定位置的比特位由0置1;

由于task_struct是内核数据结构的,只能由OS进行修改,所以可以推出

  • 无论后面有多少种产生信号的方式,最终都必须由OS来完成最后的发送过程。

二、🐧信号的捕捉

在介绍信号产生之前,我们先来谈谈信号的捕捉,以便于后面知识的理解。
前面我们提到,当我们收到一个取快递的信号时,我们可能根据场景的不同而选择执行不同的处理动作。同样的,我们因为可以通过 signal 函数来捕捉信号,让进程在接收到该信号后,不去执行默认动作(例如2号信号的默认动作的终止进程),转而执行我们的自定义动作。

signal 函数的原型如下:

#include <signal.h>

void (*signal(int signum, void (*handler)(int)))(int);
  • 参数:

    • signo:要设置处理函数的信号编号,可以是标准信号(如 SIGINT)或用户自定义的信号。
    • handler:是一个指向函数的指针,该函数接受一个整数参数,表示接收到的信号编号。
  • 返回值:

    • 返回一个指向之前信号处理函数的指针,如果之前没有设置过处理函数,则返回 SIG_DFL(默认处理)。
  • 功能:

    • signal 函数用于为指定的信号设置一个处理函数。当进程接收到指定的信号时,将调用相应的处理函数。

示例

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

using namespace std;

// 处理函数
void handler(int signo)
{
  cout << "Received SIGINT." << endl;
  _exit(1); // 直接退出
}

int main()
{
  // 注册2号信号(SIGINT)的处理函数
  signal(SIGINT, handler);
  
  while(true)
  {
    cout << "Waiting for SIGINT..." << endl;
    sleep(1);
  }
  return 0;
}
$ g++ mysignal.cc -o mysignal
$ ./mysignal 
Waiting for SIGINT...
Waiting for SIGINT...
Waiting for SIGINT...
Waiting for SIGINT...
Waiting for SIGINT...
Waiting for SIGINT...
Waiting for SIGINT...
Waiting for SIGINT...
^CReceived SIGINT.

在这个例子中,程序注册了一个用于处理 SIGINT 信号的处理函数 handler。当用户按下Ctrl+C发送SIGINT信号时,程序不会终止而是会调用这个处理函数来执行相应的操作。

注意

  • 9号信号是不能被捕捉、阻塞和忽略的。

三、🐧信号的产生

前面我们已经提到了两种信号产生的方式:键盘、kill 指令。

1.🐦键盘输入

当你在键盘上按下Ctrl+C时,这个动作实际上会产生一个中断信号,这个信号被称为SIGINT(Interrupt Signal)。操作系统内核(kernel)通过键盘驱动程序来监测键盘的输入事件。当Ctrl+C组合键被按下,键盘驱动程序会通知内核,内核然后生成一个SIGINT信号并将其发送给与当前前台进程相关联的终端。

以下是简要的工作流程:

  1. 键盘输入: 当你按下键盘上的键时,键盘控制器检测到这个事件,并将相应的扫描码发送到计算机。

  2. 中断请求(IRQ): 键盘控制器通过硬件中断请求(IRQ)通知CPU有一个新的中断事件发生。

  3. 中断服务程序: 操作系统内核中有一个与键盘输入相关的中断服务程序,它被调用以处理键盘中断。

  4. 生成信号: 中断服务程序检测到Ctrl+C组合键后,它会生成一个SIGINT信号。

  5. 信号传递: 生成的SIGINT信号被发送给当前前台进程的进程组。前台进程是与终端相关联的活跃进程。

  6. 信号处理: 如果前台进程注册了SIGINT的信号处理函数,该函数将被调用以执行相应的操作。如果没有注册处理函数,则默认操作是终止进程。

总体来说,键盘输入被硬件中断机制捕获,通过中断服务程序和信号机制,通知操作系统内核产生了一个SIGINT信号,最终传递给前台进程。

2.🐦硬件中断

当我们在程序中发生了除0、访问空指针等非法的操作时,就会引起异常,出发硬件中断被内核捕获,内核会向该进程发送信号终止该进程。

2.1 🐱除0

#include <iostream>
using namespace std;

int main()
{
  int n = 10;
  cout << n / 0 << endl;
  return 0;
}
$ g++ test.cc
$ ./a.out
Floating point exception

当在代码中进行除零操作时,会导致产生浮点异常,这将触发硬件中断。通常情况下,这个硬件中断是浮点异常中断,它会被操作系统内核捕获。内核会检查正在运行的进程是否设置了适当的信号处理函数,如果设置了,执行相应的处理操作。如果进程没有设置处理函数,通常会导致进程被终止。

以下是简要的工作流程:

  1. 除零操作: 在代码中进行除零操作时,例如浮点数除以零,将会导致浮点异常。

  2. 硬件中断: 产生的浮点异常触发了硬件中断,通常是浮点异常中断。

  3. 中断服务程序: 操作系统内核中有一个与浮点异常相关的中断服务程序,它被调用以处理浮点异常。

  4. 信号生成: 中断服务程序生成一个与浮点异常相关的信号,例如SIGFPE(浮点异常信号)。

  5. 信号传递: 生成的信号被发送给当前运行进程。

  6. 信号处理: 如果进程设置了SIGFPE的信号处理函数,该函数将被调用以执行相应的操作。如果没有设置处理函数,通常会执行默认方法导致进程被终止。

在默认情况下,如果进程没有显式设置信号处理函数来处理浮点异常,操作系统通常会终止该进程,并生成一条错误消息。这是为了防止程序执行处于未定义状态的操作,并确保系统的稳定性。

2.2 🐱访问空指针

#include <iostream>
using namespace std;

int main()
{
  int* p = NULL;
  cout << *p << endl;
  return 0;
}
$ g++ test.cc
$ ./a.out 
Segmentation fault

当代码中访问了空指针,这将导致内存访问异常,通常是由硬件中断机制引发的。这种异常会被操作系统内核捕获,并根据系统的处理策略来终止进程或采取其他适当的措施。以下是简要的工作流程:

  1. 空指针访问: 在代码中发生对空指针的访问,例如尝试读取或写入空指针指向的内存位置。

  2. 硬件中断: 产生的内存访问异常触发硬件中断,通常是由内存管理单元(MMU)检测到的。

  3. 中断服务程序: 操作系统内核中有一个与内存访问异常相关的中断服务程序,它被调用以处理异常。

  4. 信号生成: 中断服务程序可能生成一个与内存访问异常相关的信号,例如SIGSEGV(段错误信号)。

  5. 信号传递: 生成的信号被发送给当前运行进程。

  6. 信号处理: 如果进程设置了对SIGSEGV的信号处理函数,该函数将被调用以执行相应的操作。如果没有设置处理函数,通常会导致进程被终止。

在默认情况下,如果进程没有显式设置信号处理函数来处理段错误,操作系统通常会终止该进程,并在控制台或日志中记录相应的错误信息。这是为了防止程序执行处于未定义状态的操作,确保系统的稳定性,并协助开发者调试潜在的问题。

3.🐦kill 指令

我们可以用kill 想指定进程发送指令。我们除了可以直接使用kill指令向进程发送信号外,还可以在程序中调用kill函数来进行指令发送。

kill 函数是一个用于向指定进程发送信号的系统调用。它可以用于向指定进程发送任何一个有效的信号,例如终止进程、挂起进程、继续执行进程等。以下是 kill 函数的基本信息:

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

int kill(pid_t pid, int sig);
  • 参数:

    • pid:要发送信号的目标进程的进程ID。
    • sig:要发送的信号的编号,可以是标准信号(如 SIGKILL)或用户自定义的信号。
  • 返回值:

    • 如果成功,返回0;如果失败,返回-1,并设置相应的错误码(errno)。
  • 功能:

    • kill 函数用于向指定进程发送信号。信号可以是预定义的标准信号(如 SIGKILLSIGTERM)或用户自定义的信号。通常用于进程间通信、控制进程的行为,或者强制终止进程等。
  • 注意事项:

    • 如果将 pid 参数设置为0,则信号会发送给调用进程的进程组中的所有成员。
    • 如果将 pid 参数设置为-1,则信号会发送给调用进程有权发送信号的任意进程(权限通常由 effective user ID 决定)。
    • 如果发送 SIGKILL 信号(编号为9),则表示强制终止目标进程,目标进程将无法捕获或忽略该信号。

所以我们可以用kill函数来实现一个我们自己的kill指令mykill

示例

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


void Usage(string proc)
{
    cout << "Usage: \n";
    cout << proc << "信号编号 目标进程\n"
         << endl;
}
int main(int argc, char *argv[])
{
    // kill -9 xxxx
    if (argc != 3)
    {
        Usage(argv[0]);
        exit(-1);
    }

    int signo = atoi(argv[1]);
    int target_id = atoi(argv[2]);
    int n = kill(target_id, signo);
    if (n != 0)
    {
        cerr << errno << " : " << strerror(errno) << endl;
        exit(2);
    }

    return 0;
}

『Linux从入门到精通』第 ㉖ 期 - 信号概念 & 信号的产生,Linux从入门到精通,linux,redis,android

4.🐦软件条件

SIGALRM是一种由软件条件产生的信号,它可以由alarm函数产生。
alarm 函数是一个用于设置定时器的系统调用,它的主要功能是在指定的时间间隔后向进程发送 SIGALRM 信号。以下是 alarm 函数的基本信息:

#include <unistd.h>

unsigned int alarm(unsigned int seconds);
  • 参数:

    • seconds:设置定时器的时间间隔,单位是秒。当定时器计时到达指定的秒数后,将发送 SIGALRM 信号给进程。
  • 返回值:

    • 返回之前设置的剩余秒数,如果之前没有设置定时器,则返回 0。
  • 功能:

    • alarm 函数用于设置一个定时器,当定时器计时到达指定的秒数后,进程将收到 SIGALRM 信号。该信号默认会终止进程,但可以通过注册信号处理函数来改变其行为。
  • 注意事项:

    • 如果之前已经设置了定时器,调用 alarm 函数将取消之前的定时器,并用新的时间间隔重新设置。
    • 如果将 seconds 参数设置为 0,表示取消之前的定时器,即不再发送 SIGALRM 信号。

下面是一个简单的示例,演示如何使用 alarm 函数:

#include <stdio.h>
#include <signal.h>
#include <unistd.h>

void handler(int signo) {
    printf("Received SIGALRM\n");
}

int main() {
    // 注册信号处理函数
    signal(SIGALRM, alarm_handler);

    // 设置定时器,5秒后发送SIGALRM信号
    unsigned int remaining_time = alarm(5);

    printf("Timer set. Remaining time: %u seconds\n", remaining_time);

    // 进程执行其他任务
    sleep(10);

    printf("Program completed.\n");

    return 0;
}

在这个例子中,程序注册了一个用于处理 SIGALRM 信号的处理函数 alarm_handler。然后使用 alarm(5) 设置了一个5秒的定时器,5秒后将会触发 SIGALRM 信号。在实际的应用中,可以利用定时器来执行一些定时任务或超时处理。

四、🐧核心转储

我们向进程发送不同的信号,有时我们会发现有不少信号的默认执行动作是终止进程。它们之间看似效果雷同,但其实是有差别的。

使用 man 7 signal 查看signal的详细文档时,我们会看到这样的信息:

『Linux从入门到精通』第 ㉖ 期 - 信号概念 & 信号的产生,Linux从入门到精通,linux,redis,android
我们观察到有些信号的 Action 是 Term 有些是 Core,它们二者都是终止进程但是却有差别。

  • Term:单纯的终止进程,没有多余的动作
  • Core:先进性核心转储,再终止进程

🐦核心转储及其作用

核心转储(core dump)是指在程序发生严重错误导致异常终止时,操作系统将程序的内存内容以及相关的调试信息保存到一个特殊的文件中,以供后续分析和调试使用。这个文件通常被称为核心转储文件或核心文件。

核心转储文件包含了程序崩溃时内存的快照,以及与进程相关的其他信息,如寄存器状态、调用栈、变量值等。这对于开发人员来说是非常有价值的,因为它提供了关于程序崩溃原因的详细信息,有助于识别和调试问题。

核心转储文件通常以 “core” 或者在某些系统中以进程ID为文件名的形式保存在程序当前工作目录或系统指定的核心转储文件目录中。它们对于排查由于程序错误、内存损坏或其他异常情况引起的问题非常有用。

有一些关键的概念和注意事项与核心转储相关:

  1. ulimit 设置: 操作系统可能会设置 ulimit(用户资源限制)来限制核心转储文件的大小,以避免占用过多磁盘空间。

  2. 调试符号: 为了更好地解析核心转储文件,通常需要保留程序的调试符号。调试符号是编译时信息,包含了程序源代码的映射关系,有助于将内存地址映射回源代码。

  3. 调试工具: 使用调试工具(如gdb)可以加载核心转储文件,并允许开发人员分析崩溃时的状态、查看堆栈跟踪,以及检查变量值等。

  4. 产生核心转储: 在Unix-like系统中,可以通过在程序中调用 ulimit 设置允许生成核心转储文件,或者在终端运行程序时使用 ulimit -c unlimited 临时修改。

示例

在云服务器中,核心转储功能一般是关闭的,需要我们手动打开。
『Linux从入门到精通』第 ㉖ 期 - 信号概念 & 信号的产生,Linux从入门到精通,linux,redis,android

  • 打开核心转储功能;
$ ulimit -c 1024
$ ulimit -a
core file size          (blocks, -c) 1024
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 7266
max locked memory       (kbytes, -l) 64
max memory size         (kbytes, -m) unlimited
open files                      (-n) 65535
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 8192
cpu time               (seconds, -t) unlimited
max user processes              (-u) 4096
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited
  • 编写程序;
#include <iostream>

using namespace std;

int main()
{
  int *p = NULL;
  cout << *p << endl;
  return 0;
}
$ g++ test.cc -o test
$ ./test 
Segmentation fault (core dumped)
$ ll
total 248
-rw------- 1 hxy hxy 557056 Mar  6 16:54 core.6554
-rwxrwxr-x 1 hxy hxy   8920 Mar  6 16:54 test
-rw-rw-r-- 1 hxy hxy    109 Mar  6 16:54 test.cc
$
  • 当我们想调试该代码时;
$ g++ test.cc -o test -g
$ ./test
$ gdb test
GNU gdb (GDB) Red Hat Enterprise Linux 7.6.1-120.el7
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-redhat-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /home/hxy/code/test_6_23/core/test...done.
(gdb) core-file core.6753 
[New LWP 6753]
Core was generated by `./test'.
Program terminated with signal 11, Segmentation fault.
#0  0x00000000004007c1 in main () at test.cc:8
8	  cout << *p << endl;
Missing separate debuginfos, use: debuginfo-install glibc-2.17-326.el7_9.x86_64 libgcc-4.8.5-44.el7.x86_64

如上所示,当我们使用gdb加载核心转储文件时,可以直接将错误信息以及出错位置告诉我们。

早在获取子进程status时,我们曾看过一张图片:

『Linux从入门到精通』第 ㉖ 期 - 信号概念 & 信号的产生,Linux从入门到精通,linux,redis,android
当子进程被信号杀死之后,我们可以查看终止信号以及core dump标记。若core标记为0,则表示没有启用核心转储功能,若为1,则表示启用。

我们来简单验证一下:

  • 编写代码;
#include <iostream>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>

using namespace std;

int main()
{
  pid_t id = fork();
  if(id == 0)
  {
    int *p = NULL;
    cout << *p << endl;
  }
  
  int status = 0;
  waitpid(id, &status, 0);
  cout << "exit code: " << ((status >> 8) & 0xFF) << endl;
  cout << "exit signal: " << (status & 0x7F) << endl;
  cout << "core dump flag: " << ((status >> 7) & 0x1) << endl;
  return 0;
}
  • 在打开核心转储功能时,运行程序:
$ ./test 
exit code: 0
exit signal: 11
core dump flag: 1
$ ll
total 484
-rw------- 1 hxy hxy 557056 Mar  6 17:11 core.7770
-rw-rw-r-- 1 hxy hxy     78 Mar  6 17:11 makefile
-rwxrwxr-x 1 hxy hxy   9176 Mar  6 17:11 test
-rw-rw-r-- 1 hxy hxy    465 Mar  6 17:10 test.cc
  • 在关闭核心转储功能时,运行程序:
$ ulimit -c 0 # 关闭核心转储
$ ./test 
exit code: 0
exit signal: 11
core dump flag: 0

『Linux从入门到精通』第 ㉖ 期 - 信号概念 & 信号的产生,Linux从入门到精通,linux,redis,android文章来源地址https://www.toymoban.com/news/detail-840316.html

到了这里,关于『Linux从入门到精通』第 ㉖ 期 - 信号概念 & 信号的产生的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Linux入门之进程信号|信号产生的方式

    文章目录 一、信号入门 1.linux信号的基本概念 2.使用kill -l 命令可以查看系统定义的信号列表 3.信号处理常见方式 二、产生信号 1.通过终端按键产生信号 2.通过调用系统函数向进程发信号 3.由软条件产生信号 4.硬件异常产生信号     1. /0异常     2.模拟野指针 信号是进程之

    2024年02月09日
    浏览(43)
  • 【Linux从入门到精通】信号(信号保存 & 信号的处理)

      本篇文章接着信号(初识信号 信号的产生)进行讲解。学完信号的产生后,我们也了解了信号的一些结论。同时还留下了很多疑问: 上篇文章所说的所有信号产生,最终都要有OS来进行执行,为什么呢? OS是进程的管理者 。 信号的处理是否是立即处理的? 在合适的时候。

    2024年02月09日
    浏览(43)
  • 【Linux从入门到精通】进程的基本概念

        我们通过对上篇文章冯诺依曼体系结构对硬件进行讲解后, 本篇文章会对进程进行深入讲解。同时会讲解PCB(进程控制块)。希望本篇文章内容会对你有所帮助。 文章目录 一、再次理解操作系统 1、1 操作系统的作用 1、2 操作系统的管理 二、进程基本的概念 2、1 什么是

    2024年02月05日
    浏览(48)
  • 【Linux从入门到精通】信号量(信号量的原理与相关操作接口)详解

      本篇文章重点对 信号量的概念,信号量的申请、初始化、释放、销毁等操作进行讲解。同时举例把信号量应用到生产者消费者模型来理解 。希望本篇文章会对你有所帮助。 目录 一、信号量概念 1、1 什么是信号量 1、2 为什么要有信号量 1、3 信号量的PV操作 二、信号量的相

    2024年02月08日
    浏览(48)
  • 【Linux从入门到精通】上下文概念详解

        上篇文章(进程的基本概念)我们讲解了进程后,还留下了一个上下文数据概念还没有解释。本篇文章会对上下文概念进行详解。在理解上下文概念时,同时会引出很多新的概念。我们都会对此进行详细解释,希望本篇文章会对你有所帮助。  文章目录  一、什么是上下

    2024年02月05日
    浏览(48)
  • 【Linux从入门到精通】一文带你理解进程概念

        我们通过对上篇文章冯诺依曼体系结构对硬件进行讲解后, 本篇文章会对进程进行深入讲解。同时会讲解PCB(进程控制块)。希望本篇文章内容会对你有所帮助。 文章目录 一、再次理解操作系统 1、1 操作系统的作用 1、2 操作系统的管理 二、进程基本的概念 2、1 什么是

    2024年02月04日
    浏览(40)
  • Linux进程信号【信号产生】

    ✨个人主页: 北 海 🎉所属专栏: Linux学习之旅 🎃操作环境: CentOS 7.6 阿里云远程服务器 在 Linux 中,进程具有独立性,进程在运行后可能 “放飞自我”,这是不利于管理的,于是需要一种约定俗成的方式来控制进程的运行,这就是 进程信号 ,本文将会从什么是进程信号

    2024年02月11日
    浏览(47)
  • 【linux】信号——信号产生

    自我名言 : 只有努力,才能追逐梦想,只有努力,才不会欺骗自己。 喜欢的点赞,收藏,关注一下把! 首先说明一点信号不是信号量。不能把这两个东西放在一起。 那信号讲什么呢? 那信号是怎么回事,这里只能这样说, 信号是针对进行发送某种信号到来的一种机制,让

    2024年02月05日
    浏览(42)
  • Linux进程(一)信号-----信号产生

    在  Linux  中,进程具有独立性,进程在运行后可能 “放飞自我”,这是不利于管理的,于是需要一种约定俗成的方式来控制进程的运行,这就是  进程信号 ,本文将会从什么是进程信号开篇,讲述各种进程信号的产生方式及作用。 信号 是信息传递的承载方式,一种信号往

    2024年02月21日
    浏览(50)
  • 【Linux】第八讲:Linux进程信号详解(一)_ 认识信号 | 产生信号

    「前言」文章是关于Linux进程信号方面的知识,本文的内容是Linux进程信号第一讲,讲解会比较细,下面开始! 「归属专栏」Linux系统编程 「主页链接」个人主页 「笔者」枫叶先生(fy)  「枫叶先生有点文青病」「每篇一句」  人生天地间,忽如远行客。 ——《乐府·青青陵上

    2023年04月25日
    浏览(49)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包