【Linux】进程通信 — 信号(上篇)

news2024/11/18 12:16:37

文章目录

  • 📖 前言
  • 1. 什么是信号
    • 1.1 认识信号:
    • 1.2 信号的产生:
    • 1.3 信号的异步:
    • 1.4 信号的处理:
  • 2. 前后台进程
  • 3. 系统接口
    • 3.1 signal:
      • 3.1 - 1 不能被捕捉的信号
    • 3.2 kill:
      • 3.2 - 1 killall
    • 3.3 raise:
    • 3.4 abort:
    • 3.5 alarm:
  • 4. 崩溃的本质是什么
    • 4.1 Core Dump:

📖 前言

本章我们将讲解Linux信号这部分的内容,本章将介绍信号的产生,发送,信号的捕捉,屏蔽等操作,将对信号进行一些列系统的了解与学习。目标已经确定,接下来就要搬好小板凳,准备开讲了…🙆🙆🙆🙆


1. 什么是信号

1.1 认识信号:

  • 在我们学习信号之前,我们先来回忆一下生活中的各种信号,例如:红绿灯、铃声、闹钟……
  • 我们在能够认识这些场景下的信号以及所表示的含义:
    • 即便这个信号还没有产生,我们就已经具备了处理这个信号的能力。
  • 我们早就知道了信号产生后要做什么:
    • 即便当前信号还没有产生,我们已经提前知道了这个信号的处理方法。
  • 信号是给进程发送的,进程要具备处理信号的能力。
  • 可以说程序员通过编写代码来利用操作系统提供的接口和功能,实现了处理信号的能力。
    • 该能力一定是预先已经早就有了的。
    • 进程能够识别对应的信号。
    • 进程能够处理对应信号。

对于进程来讲,即便是信号还没有产生,我们进程已经具有识别和处理这个信号的能力了。

  • 信号的种类:

使用kill -l命令罗列出来的内容叫做信号,我们可以看到目前Linux系统下64种不同的类型:

在这里插入图片描述

  • 没有32、33、0号信号。
  • 第一批1 ~ 31(普通信号)
  • 第二批34 ~ 64(实时信号)

信号左侧的数字和右侧的名称是一回事,其实都是宏,大写的字母是宏名称,宏的值就是左侧对应的编号。

这二者的差别是:早期有实时操作系统,我们现在用的是分时操作系统。
基于时间片轮转,基于优先级抢占的调度算法。

1.2 信号的产生:

有很多情况会产生信号:

  1. 系统接口(kill命令)
  2. 键盘产生(Ctrl + C,Ctrl + \ )
  3. 软件条件(进程停止,进程运行完退出)
  4. 硬件异常(比如除0错误)

信号发送的本质:

  • 键盘是产生了信号,但是信号是操作系统发的。
  • 在位图中,将对应的位置设置为1,就完成了信号的发送。
  • 与其叫发送,不如叫操作系统向进程写入信号。

信号都是由操作系统向系统写入的:

  • 计算机要是想向一个PCB进程发信号,本质上因为操作系统是进程的管理者。
  • 可以直接以自身的身份来对进程的PCB数据结构的位图做任意修改。

崩溃现象就是底层代码引起了硬件的问题,进而被操作系统识别,然后操作系统将硬件问题识别成信号,然后向进程发送,然后终止进程。

1.3 信号的异步:

何为异步:

以点外卖为例,当外卖到了时,你可能正在忙着做其他事情,外卖员给你发了条取餐消息,但是你并不能立即去取。
此时我们知道自己的外卖到了(知道收到了信号),等手上的活忙完了再去取(过一会再去处理信号)。

同步和异步:

  • 当节奏会受某个因素影响时,这叫同步。
  • 当节奏不会受某个因素影响时,这叫异步。

信号可能在任何时候都能产生,可能是用户产生,也可能是操作系统产生的,这个产生对进程来讲是异步的。

因为信号产生是异步的:

  • 当信号产生的时候,对应的进程可能正在做更重要的事情,我们进程可以暂时不处理这个信号!
  • 也就是说进程可能不需要立即处理这个信号!
  • 但是并不代表这个信号不会被处理!

1.4 信号的处理:

处理信号的三种行为:

  1. 默认动作。
  2. 忽略。
  3. 自定义动作。

信号的处理,也叫做信号的的捕捉,递达处理动作。

必须记住这个信号有没有,是什么信号:

  • 信号被记录在了进程的PCB当中的:
    • 有没有产生【比特位的内容1/0】
    • 是什么信号产生【比特位的位置】

只有操作系统有这个权利,能直接修改这个task_struct内的数据位图!
OS是进程的管理者,进程的所有的属性的获取和设置,只能由OS来!!
无论信号怎么产生,最终一定只能是OS帮我们进行信号的设置的!


2. 前后台进程

Ctrl + C的本质是向前台进程发送信号。

在这里插入图片描述
我们死循环打印Hello World,在一直死循环期间,我们输入命令ls并不会列出该目录下的文件名。

myproce跑起来之后,再输入其他指令是没用的,因为这个进程占用了前面bash所对应的终端。当前bash没法做命令行响应,此时这种进程叫做前台进程。

将进程放到后台:

在这里插入图片描述

26733是进程编号。

后台进程,可以执行命令行指令,但是用Ctrl + C终止不了了。

在这里插入图片描述
jobs查看后台进程:

在这里插入图片描述

fg 1就将该进程提至前台了,再次Ctrl + C就可以了。

补充:

  • 前后端混打的时候,虽然会打印乱掉,混乱是很正常的因为缺少访问控制,信息交叉在一起。根据冯·诺依曼体系,我们输入的内容一定是先被进程拿到的,显示器之所以能看到,是因为给显示器也拷贝了一份,这叫回显。
  • 不回显也可以的,就像Linux输入密码,不回显但是确实输进去了。

任务管理:

在这里插入图片描述
在Linux中,作业列表中的符号+-表示了作业的状态。

  • 符号"+"表示当前前台运行的作业。
  • 符号"-"表示当前后台运行的作业。

如果没有"+“和”-"符号显示在作业列表中,则表示当前没有前台或后台运行的作业。作业列表可能是空的,也就是没有任何正在运行的作业。这通常发生在你没有在前台执行命令或将任何作业放到后台时

bg指令:
要将一个正在前台运行的作业切换到后台运行,可以按下"Ctrl + Z",这会将该作业暂停,并返回到命令行界面。然后,可以使用"bg"命令将作业放到后台继续运行,此时作业会继续执行,但不会再占用终端。


3. 系统接口

3.1 signal:

在这里插入图片描述

Ctrl + C是向前台发送二号信号。

代码演示:

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

using namespace std;

void handler(int signo)
{
    cout << "我是一个进程,刚刚获取了一个信号: " << signo << endl;
}

int main()
{
    // 给该信号设置了回调捕捉,自定义动作
    // 这里不是调用handler方法,这里只是设置了一个回调,让SIGINT产生的时候,该方法才会被调用。
    // 如果不产生SIGINT,该方法不会被调用!
    // 当二号信号产生的时候,才调用后面的方法。
    signal(SIGINT, handler);
    signal(3, handler);

    sleep(3);
    cout << "进程已经设置完了" << endl; 

    sleep(3);

    while (true)
    {
        cout << "我是一个正在运行中的进程: " << getpid() << endl;
        sleep(1);
    }
    return 0;
}

注意:

  • 给该信号设置了回调捕捉,自定义动作。
  • 这里不是调用handler方法,这里只是设置了一个回调,让SIGINT产生的时候,该方法才会被调用。
  • 如果不产生SIGINT,该方法不会被调用!!
  • 当二号信号产生的时候,才调用后面的方法。

函数指针,回调函数:

  • 函数指针类型,允许用户对信号自定义处理,忽略,自定义,默认。
  • 大部分信号都有默认动作,而signal方法可以让进程对特定的信号自定义设置。

在这里插入图片描述

  • Ctrl + C本质是给前台产生了2号信号,发送给目标进程,其中目标进程默认对2号信号的处理,是终止自己。
  • 更改了对二号信号处理,设置了用户自定义处理方法。
  • 还有一种终止进程的方法是发送3号信号

3.1 - 1 不能被捕捉的信号

  • 到这里我们不禁思索一番,我们之前讲过kill -9 + 进程ID信号可以杀掉进程,那我们能否将kill -9 + 进程ID的信号捕捉了呢?
  • 经过实验,得到结论,kill -9 + 进程ID该信号并不能被捕捉,这是为了防止一些恶意进程杀不掉的情况。
  • 因为9号信号不能被设置捕捉动作。永远都是默认动作,叫做管理员信号。
  • 9号信号几乎可以杀掉所有进程,除了曾经讲的D状态的进程。进程状态复习-传送门
  • 在Linux中,有一些信号被称为"不可捕捉信号",它们无法被用户进程捕捉或处理。这些信号是:
  • SIGKILL (信号编号为9):用于立即终止一个进程。无论进程是否希望接收该信号,都无法阻止或忽略它。
  • SIGSTOP (信号编号为19或17):用于暂停一个进程的执行。与SIGKILL类似,无法被捕捉或忽略。
  • SIGCONT (信号编号为18或19):用于继续一个被暂停的进程的执行。与前两个信号不同,SIGCONT是可以被捕捉的,但在默认情况下,它会立即恢复进程的执行。

这些不可捕捉信号通常由操作系统或其他系统级实体发送,用于管理进程的状态和行为。在正常情况下,用户进程无法阻止或修改这些信号的执行。

3.2 kill:

kill不仅是命令而且也是系统调用接口:

在这里插入图片描述

  • 向指定进程发送指定信号,成功了返回0,失败了返回-1。
  • 支持向任意进程发送任意信号。
  • 杀进程也是要有权限的。

不能杀掉不是自己的进程:

在这里插入图片描述
有了上述接口,再加上我们之前学的main函数的几个参数,我们可以手搓一个kill指令:

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

using namespace std;

static void Usage(const string& proc)
{
    cout << "Usage:\n\t" << proc << "signo pid" << endl;
}

// 自己实现一个kill命令
// mykill 9 1234
int main(int argc, char* argv[])
{
    if (argc != 3)
    {
        Usage(argv[0]);
        exit(1);
    }

    if (kill(static_cast<pid_t>(atoi(argv[2])), atoi(argv[1])) == -1)
    {
        cerr << "kill: " << strerror(errno) << endl;
        exit(2);
    }
    
    return 0;
}

3.2 - 1 killall

根据进程名字杀掉某个进程:killall + 进程名

  • 在Linux中,killall命令用于终止同名进程。
  • killall命令默认会发送SIGTERM(信号编号为15)信号给目标进程。
  • 不过,你也可以使用参数"-s"或"–signal"来指定其他信号,例如SIGKILL(信号编号为9)。
  • 这个命令非常有用,特别是当你想要快速终止所有同名进程时。
  • 需要注意的是,使用killall命令要小心,确保只终止你想要终止的进程,以免造成意外的影响。

3.3 raise:

kill是给任意进程发任意信号,raise是给自己发任意信号:

在这里插入图片描述
进程不断地给自己发送2号信号:

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

using namespace std;

void handler(int signo)
{
    cout << "我是一个进程,刚刚获取了一个信号: " << signo << endl;
}

int main()
{
    // 这里没有调用对应的handler方法,仅仅是注册
    
    signal(2, handler);

    while (true)
    {
        // 每次循环都给自己发送2号信号
        sleep(1);
        raise(2);
    }
    // 每隔1秒都会收到一个2号信号

    return 0;
}

在这里插入图片描述

3.4 abort:

向自己发送6号SIGABRT信号:

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

using namespace std;

void handler(int signo)
{
    cout << "我是一个进程,刚刚获取了一个信号: " << signo << endl;
}

int main()
{
    // 这里没有调用对应的handler方法,仅仅是注册
    
    signal(6, handler);

    while (true)
    {
        sleep(1);
        abort();// exit(), ahort();
    }

    return 0;
}

终止进程:

在这里插入图片描述
注意:

  • abort()是即使捕捉了,但是依然会退出进程。
  • 除了9号信号不能被捕捉,对6号信号进行捕捉,但是依旧会退出。

硬件是在推着操作系统做一系列动作:

  • 时钟硬件 —— 给操作系统发送时钟中断。
  • CPU主频越高调度的频率就越高,效率就越高。

3.5 alarm:

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

using namespace std;
    
int cnt = 0;

void handler(int signo)
{
    cout << "我是一个进程,刚刚获取了一个信号: " << signo << "cnt: " << cnt << endl;
    exit(1);
}

// 信号闹钟
int main()
{
    // 未来一秒钟之后会超时

    signal(SIGALRM, handler);

    alarm(1);
    // 如果没有自定义操作,默认alarm会自定义终止,会收到SIGALRM信号

    // 统计该进程一秒钟cnt++多少次
    while (1)
    {
        cnt++;
        // cout << "hello: " << cnt++ << endl;
    }

    return 0;
}

相比于CPU独立做计算,IO非常慢。

在这里插入图片描述

  • 在Linux中,默认情况下,当alarm定时器到期时,会生成一个SIGALRM信号。 如果进程没有捕获和处理该信号,那么该进程会被终止。
  • SIGALRM信号是用于告知进程某个定时器已经超时的信号。它通常由内核或通过使用alarm函数设置的定时器触发。当定时器超时时,内核向进程发送SIGALRM信号,进程可以选择捕获和处理该信号,或者使用默认操作(即终止进程)。
  • 如果进程没有显式地设置对SIGALRM信号的处理方式(通过信号处理函数或信号处理器),那么SIGALRM信号将以默认操作的方式处理,即终止进程。这意味着如果定时器超时并且进程没有捕获该信号,进程会被终止。

4. 崩溃的本质是什么

在Linux中越界访问都叫段错误。

所谓的崩溃,本质是什么呢?

  • 是该进程收到了异常信号,应该叫进程崩溃了。

进程崩溃是因为收到了异常信号,那么为什么会收到异常信号呢?

  • 除零问题:计算是在CPU内部,内有状态寄存器,该寄存器是用来表征该本次计算是否出现问题。
  • 如果有问题,状态寄存器中特定标志位会被计位。

C++ try catch:

  • 崩溃了,一定会导致进程终止吗?不一定!!
    • 崩溃,本质是什么呢?
    • 进程崩溃的本质,是该进程收到了异常信号!
  • 为什么呢?
  • 因为硬件异常,而导致OS向目标进程发送信号,进而导致进程终止的现象!
    • 除零: CPU内部,状态寄存器,当我们除0的时候,CPU内的状态寄存器会被设置成为,有报错:浮点数越界,CPU的内部寄存器(硬件),OS就会识别到CPU内有报错啦:
      • 1.谁干的?2.是什么报错(OS -> 构建信号) -> 目标进程发送信号 -> 目标进程在合适的时候 -> 处理信号 -> 终止进程。
    • 越界 && 野指针: 我们在语言层面使用的地址(指针),实都是虛拟地址 -> 物理地址 -> 物理内存 -> 读取对应的数据和代码的。
    • 如果虚拟地址有问题,地址转化的工作是由(MMU(硬件) + 页表(软件)),转化过程就会引起问题 -> 表现在硬件MMU上 -> OS发现硬件出现了问题:
      • 1.谁干的?2.是什么报错(OS -> 构建信号) -> 目标进程发送信号 -> 目标进程在合适的时候 -> 处理信号 -> 终止进程。

MMU是内存管理单元(Memory Management Unit)的简称。

实操注意:

  • 当进程崩溃时,对某个信号进行时捕捉时:
    • 要将自定义的handler函数最后exit(1);退出进程,不然会一直发信号,就会一直调用handler函数。
    • 因为一般进程崩溃时,操作系统会给进程发送对应的信号并终止进程。

在这里插入图片描述

  • 如果不加上最后的退出进程,会一直打印刷屏。
  • 一旦我们不进行信号捕捉,会直接终止。
  • 而我们捕捉之后如果没有对信号做处理,没有终止进程的话,会一直刷屏,进程没有被终止。

因为没有解决这个问题,这个异常一直都在,所以操作系统一直给进程发信号,所以刷屏了。

4.1 Core Dump:

Core Dump会把进程在运行中,对应的异常上下文数据,core dump到磁盘上,方便调试。

发上云服务器是设置成0的,禁止发生core dump(一般是关掉的),但是可以打开。

打开方式:

在这里插入图片描述
Core不光光要终止,还要发生Core dump。

在这里插入图片描述
8号信号本身就要产生core文件的,然后指令发现多了一个文件,里面是乱码。

在这里插入图片描述
当一个进程异常退出时,收到了某些信号,系统为了便于用户调试,会告诉用户触发core dump机制,core dump机制叫做核心转储。

在这里插入图片描述

核心转储(Core Dump)是指在程序运行过程中发生了严重错误导致程序崩溃时,系统将程序内存的完整快照保存到一个核心转储文件中。

  • 这个文件包含了程序崩溃时的内存状态、寄存器的内容以及其他相关的调试信息。
  • 核心转储文件主要用于程序崩溃分析和调试目的。通过分析核心转储文件,开发人员可以了解程序崩溃时的内存状态,定位错误的原因,并进行问题排查和修复。
  • 核心转储文件通常具有可读性较低的二进制格式,需要使用调试工具或分析器来解析和分析。
  • 在许多操作系统上,默认情况下,当程序崩溃时会自动生成核心转储文件。开发人员也可以在程序中通过设置相应的参数或使用调试工具来控制核心转储的生成及其行为。
  • 需要注意的是,由于核心转储文件可能会包含敏感信息,如内存中的数据,因此在进行排查和分析时需要遵守相应的隐私保护规定,并确保核心转储文件的安全性。

生成的Core Dump文件很大:

在这里插入图片描述

Core Dump一般配台gdb使用:

在这里插入图片描述
每次执行出错都会产生core dump文件,这种调试策略叫做事后调试。

云服务器关掉的原因:

因为如果大型程序,一旦代码有问题,会自动重启程序,如果一重启就挂掉,就会产生core文件,所以一直重启就会产生大量的core文件,就很大概率将磁盘空间被打满,此时就会危及到操作系统正常工作了。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

15.live555mediaserver-rtp打包

live555工程代码路径 live555工程在我的gitee下&#xff08;doc下有思维导图、drawio图&#xff09;&#xff1a; live555 https://gitee.com/lure_ai/live555/tree/master 章节目录链接 0.前言——章节目录链接与为何要写这个&#xff1f; https://blog.csdn.net/yhb1206/art…

每天一道动态规划——第一天

动态规划一定要去尝试&#xff01;题目一&#xff1a; 1&#xff09;题目描述 一共有N个位置&#xff0c;机器人从当前位置cur走到目标位置aim&#xff0c;有res步可以走&#xff0c;问一共有多少种方法。 题目示例&#xff1a; 1 2 3 4 5 6 N6|cur2|aim3|res3 结果&#xf…

suricata初体验+wireshark流量分析

目录 一、suricata介绍 1.下载安装 2.如何使用-攻击模拟 二、wireshark流量分析 1.wireshark过滤器使用 2.wireshark其他使用 一、suricata介绍 1.下载安装 通过官网下载suricata&#xff0c;根据官网步骤进行安装。 官网地址&#xff1a; https://documentation.wazuh.…

Python高光谱遥感数据处理与高光谱遥感机器学习方法应用

本文提供一套基于Python编程工具的高光谱数据处理方法和应用案例。 本文涵盖高光谱遥感的基础、方法和实践。基础篇以学员为中心&#xff0c;用通俗易懂的语言解释高光谱的基本概念和理论&#xff0c;旨在帮助学员深入理解科学原理。方法篇结合Python编程工具&#xff0c;专注…

二叉树的层序遍历及完全二叉树的判断

文章目录 1.二叉树层序遍历 2.完全二叉树的判断 文章内容 1.二叉树层序遍历 二叉树的层序遍历需要一个队列来帮助实现。 我们在队列中存储的是节点的地址&#xff0c;所以我们要对队列结构体的数据域重定义&#xff0c; 以上代码 从逻辑上来讲就是1入队&#xff0c;1出队&am…

【信创】未写完

信创比赛 模块A任务二&#xff1a;docker容器集群管理 模块C子任务一:数据库部署子任务二:数据库参数配置子任务三&#xff1a;数据库管理 模块A 任务二&#xff1a;docker容器集群管理 1.docker run 新建创建容器 2.docker loan 将文件导入镜像库里&#xff08;将该文件变成镜…

DDR PHY

1.ddr phy架构 1.pub&#xff08;phy unility block&#xff09; 支持特性&#xff1a; &#xff08;1&#xff09;不支持SDRAM的DLL off mode &#xff08;2&#xff09;数据位宽是以8bit逐渐递增的&#xff08;这样做的目的是因为可能支持16/32/64bit的总线位宽&#xff…

STM32F103 4G Cat.1模块EC200S使用

一、简介 EC200S-CN 是移远通信最近推出的 LTE Cat 1 无线通信模块&#xff0c;支持最大下行速率 10Mbps 和最大上行速率 5Mbps&#xff0c;具有超高的性价比&#xff1b;同时在封装上兼容移远通信多网络制式 LTE Standard EC2x&#xff08;EC25、EC21、EC20 R2.0、EC20 R2.1&a…

QtCreator指定Windows Kits版本

先说下事件起因&#xff1a;之前一直在用Qt5.12.6&#xff0b;vs2017在写程序&#xff0c;后面调研了一个开源库Qaterial&#xff0c;但是翻来覆去的编译都有问题&#xff0c;后面升级到了Qt5.15.2&#xff0b;vs2019来进行cmake的编译&#xff0c;搞定了Qaterial&#xff0c;但…

家长如何将ChatGPT成为家庭日常活动的得力助手

人工智能已经在许多领域发挥作用&#xff0c;如播放音乐、关闭灯光和帮助我们更安全地驾驶。那么&#xff0c;在养育孩子方面呢&#xff1f; 使用像ChatGPT这样的应用&#xff0c;家长们可以更好地完成任务&#xff0c;但同时也要了解其中存在的风险。 许多家长表示&#xff…

KVM创建虚拟机可访问外网+可使用Xshell等工具连接

创建虚拟机时使用桥接网络模块即可&#xff0c;如下&#xff1a; 1、创建一个存储卷(虚拟机的磁盘) 2、创建虚拟机时选择网络 3、系统安装完成后配置固定IP地址 vi /etc/sysconfig/network-scripts/ifcfg-eth0ONBOOTyes BOOTPROTOstatic IPADDR16.32.15.60 GATEWAY16.32.15.2…

【JasperReport笔记05】JasperReport指定自定义字体文件,解决中文不显示问题

这篇文章&#xff0c;主要介绍JasperReport指定自定义字体文件&#xff0c;解决中文不显示问题。 目录 一、自定义字体文件 1.1、创建字体配置文件 1.2、创建fonts.xml字体文件 1.3、在Jasper Studio中添加字体 1.4、指定模板文件 1.5、案例代码 1.6、运行测试 1.7、服…

Base64与cv2读取的图片,格式互转

Base64编码 Base64编码是一种将二进制数据转换为可打印字符的方式&#xff0c;以便在文本格式中传输或存储。它通常用于将二进制数据编码为ASCII字符串&#xff0c;以便在电子邮件、网页或XML文件中传输。 Base64编码的原理是将3个8位字节的数据&#xff08;即24位二进制数据…

最近在干什么

不知不觉这个月要过去一大半了&#xff0c;说好的一个月更新一两篇博客又要食言了。就来随便聊聊最近在干的事吧。 以图说话&#xff0c;作为程序员还有什么比 Git 提交记录更好说明你最近工作状态的呢。 当然这里所有的提交记录仅仅来自一个 Repository (库) &#xff0c;就是…

【Acwing338】计数问题题解

题目描述 举个栗子分类讨论 求a~b中x的个数&#xff0c;可以转换为1~b中x的个数减去1~a-1中x的个数 所以核心是求1~n中x的个数&#xff0c;可以转换为求x在1~n中每一个数的每一位上出现的次数的和 假设要求1~abcdefg&#xff08;这是一个七位数&#xff09;中x1的个数&#…

Shell基础_Shell概述及脚本执行方式

文章目录 1. Shell概述1.1 Shell是什么1.2 Shell的分类1.3 Linux支持的Shell1.4 总结 2. Shell脚本的执行方式2.1 echo输出命令2.2 第一个脚本2.3 脚本执行 1. Shell概述 1.1 Shell是什么 Shell是一个命令行解释器&#xff0c;它为用户提供了一个向Linux内核发送请求以便运行…

深度学习8:详解生成对抗网络原理

目录 大纲 生成随机变量 可以伪随机生成均匀随机变量 随机变量表示为操作或过程的结果 逆变换方法 生成模型 我们试图生成非常复杂的随机变量…… …所以让我们使用神经网络的变换方法作为函数&#xff01; 生成匹配网络 培养生成模型 比较基于样本的两个概率分布 …

结合源码拆解Handler机制

作者&#xff1a;Pingred 前言 当初在讲App启动流程的时候&#xff0c;它的整个流程涉及到的类可以汇总成下面这张图&#xff1a; 那时着重讲了AMS、PMS、Binder这些知识点&#xff0c;有一个是没有对它进行详细讲解的&#xff0c;那就是常见的Handler&#xff0c;它不仅在这个…

一篇掌握BFD技术(一):静态路由与BFD联动配置

1. 实验目的 熟悉静态路由与BFD联动的应用场景掌握静态路由与BFD联动的配置 2. 实验拓扑 想要华为数通配套实验拓扑和配置笔记的朋友们点赞关注&#xff0c;评论区留下邮箱发给你 3. 实验步骤 1&#xff09;配置IP地址 AR1的配置 <Huawei>system-view Enter system…

Linux——socket网络通信

一、什么是socket Socket套接字 由远景研究规划局&#xff08;Advanced Research Projects Agency, ARPA&#xff09;资助加里福尼亚大学伯克利分校的一个研究组研发。其目的是将 TCP/IP 协议相关软件移植到UNIX类系统中。设计者开发了一个接口&#xff0c;以便应用程序能简单地…