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

文章目录

  • 📖 前言
  • 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.mfbz.cn/a/90859.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Vue3.0极速入门- 目录和文件说明

目录结构 以下文件均为npm create helloworld自动生成的文件目录结构 目录截图 目录说明 目录/文件说明node_modulesnpm 加载的项目依赖模块src这里是我们要开发的目录&#xff0c;基本上要做的事情都在这个目录里assets放置一些图片&#xff0c;如logo等。componentsvue组件…

巨人互动|Facebook海外户Facebook游戏全球发布实用策略

Facebook是全球最大的社交媒体平台之一&#xff0c;拥有庞大的用户基数和广阔的市场。对于游戏开发商而言&#xff0c;利用Facebook进行全球发布是一项重要的策略。下面小编将介绍一些实用的策略帮助开发商在Facebook上进行游戏全球发布。 巨人互动|Facebook海外户&Faceboo…

Maven的超级POM

对于我们创建的一个maven工程&#xff0c;即便我们自己的pom.xm文件中没有明确指定一个父工程&#xff08;父POM&#xff09;&#xff0c;其实也默认继承了超级POM&#xff0c;就好比JAVA类继承Object类一样。 maven官网关于超级POM的介绍&#xff1a; https://maven.apache.o…

3.BGP状态机和路由注入方式

BGP状态机 BGP路由的生成 不同于IGP路由协议,BGP自身并不会发现并计算产生路由,BGP将GP路由表中的路由注入到BGP路由表中,并通过Update报文传递给BGP对等体。 BGP注入路由的方式有两种: Networkimport-route与IGP协议相同,BGP支持根据已有的路由条目进行聚合,生成聚合路由…

关于css 的选择器和 css变量

css 选择器 常用的选择器 1. 后代选择器&#xff1a;也就是我们常见的空格选择器&#xff0c;选择的对象为该元素下的所有子元素 。例如&#xff0c;选择所有 元素下的 元素 div p{font-size:14px}2. 子元素选择器 ‘>’ 选择某元素下的直接子元素。例如&#xff0c;选择所…

stm32之8.中断

&#xff08;Exceptions&#xff09;异常是导致程序流更改的事件&#xff0c;发生这种情况&#xff0c;处理器将挂起当前执行的任务&#xff0c;并执行程序的一部分&#xff0c;称之为异常处理函数。在完成异常处理程序的执行之后&#xff0c;处理器将恢复正常的程序执行&#…

PyQt open3d 加载 显示点云

PyQt加载 显示点云&#xff0c;已经有三种方式&#xff0c;使用 open3d; 使用 vtk; 使用 pcl; 下面是使用 open3d: import sys import open3d as o3d import numpy as np import pyqtgraph.opengl as gl from PyQt5.QtWidgets import QApplication, QVBoxLayout, QWidget, QFi…

LeetCode 138.复制带随机指针的链表

文章目录 &#x1f4a1;题目分析&#x1f4a1;解题思路&#x1f6a9;步骤一&#xff1a;拷贝节点插入到原节点的后面&#x1f369;步骤一代码 &#x1f6a9;步骤二&#xff1a;控制拷贝节点的random进行连接&#x1f369;步骤二代码 &#x1f6a9;步骤三&#xff1a;拷贝节点解…

Linux 内核page migration设计文档

概述 page migration设计之初是在numa system的各个node之间迁移physical pages&#xff0c;意味着进程页面的虚拟地址不会变化&#xff0c;物理地址发生改变&#xff0c;migration的目的将page迁移到临近的cpu上降低内存访问延迟。 页面迁移粗略步骤 A. In kernel use of m…

4.14 tcp_tw_reuse 为什么默认是关闭的?

开启 tcp_tw_reuse 参数可以快速复用处于 TIME_WAIT 状态的 TCP 连接时&#xff0c;相当于缩短了 TIME_WAIT 状态的持续时间。 tcp_tw_reuse 是什么&#xff1f; TIME_WAIT 状态的持续时间是 60 秒&#xff0c;这意味着这 60 秒内&#xff0c;客户端一直会占用着这个端口。端…

桃子叶片病害识别(Python代码,pyTorch框架,深度卷积网络模型,很容易替换为其它模型,带有GUI识别界面)

1.分为三类 健康的桃子叶片 &#xff0c;251张 桃疮痂病一般&#xff0c;857张 桃疮痂病严重&#xff0c;770 张 2. GUI界面识别效果和predict.py识别效果如视频所示桃子叶片病害识别&#xff08;Python代码&#xff0c;pyTorch框架&#xff0c;深度卷积网络模型&#xff0…

探索图结构:从基础到算法应用

文章目录 理解图的基本概念学习图的遍历算法学习最短路径算法案例分析&#xff1a;使用 Dijkstra 算法找出最短路径结论 &#x1f389;欢迎来到数据结构学习专栏~探索图结构&#xff1a;从基础到算法应用 ☆* o(≧▽≦)o *☆嗨~我是IT陈寒&#x1f379;✨博客主页&#xff1a;I…

光伏+旅游景区

传统化石燃料可开发量逐渐减少&#xff0c;并且对环境造成的危害日益突出。全世界都把目光投向了可再生能源&#xff0c;希望可再生能源能够改变人类的能源结构。丰富的太阳能取之不尽、用之不竭&#xff0c;同时对环境没有影响&#xff0c;光伏发电是近些年来发展最快&#xf…

淘宝商品数据采集(如何快速获取淘宝商品信息),淘宝API接口申请指南

淘宝作为国内的电商平台&#xff0c;拥有海量的商品信息。对于想要进行淘宝商品数据采集的人来说&#xff0c;如何快速获取淘宝商品信息是一个重要的问题。本文将介绍一些快速获取淘宝商品信息的方法。 1. 使用淘宝开放平台PI 淘宝开放平台提供了多种PI接口&#xff0c;可以通…

<C++> 内存管理

1.C/C内存分布 让我们先来看看下面这段代码 int globalVar 1; static int staticGlobalVar 1; void Test() {static int staticVar 1;int localVar 1;int num1[10] {1, 2, 3, 4};char char2[] "abcd";char *pChar3 "abcd";int *ptr1 (int *) mal…

【Git】学习总结

【Git】学习总结 【一】安装【二】Git克隆项目代码【1】idea下载git项目【2】创建新的分支【3】新建的分支推送到远程【4】合并最新代码到主分支【5】切换分支 【三】提交本地项目到远程&#x1f680;1. 配置 Git&#x1f680;2. 创建项目远程仓库&#x1f680;3. 初始化本地仓…

vue2 生命周期,工程化开发入门

一、今日目标 1.生命周期 生命周期介绍生命周期的四个阶段生命周期钩子声明周期案例 2.工程化开发入门 工程化开发和脚手架项目运行流程组件化组件注册 二、Vue生命周期 思考&#xff1a;什么时候可以发送初始化渲染请求&#xff1f;&#xff08;越早越好&#xff09;什么…

Hightopo 使用心得(6)- 3D场景环境配置(天空球,雾化,辉光,景深)

在前一篇文章《Hightopo 使用心得&#xff08;5&#xff09;- 动画的实现》中&#xff0c;我们将一个直升机模型放到了3D场景中。同时&#xff0c;还利用动画实现了让该直升机围绕山体巡逻。在这篇文章中&#xff0c;我们将对上一篇的场景进行一些环境上的丰富与美化。让场景更…

docker搭建opengrok环境2

引言&#xff1a; 虚拟机关闭后重新开启&#xff0c;理论上是需要重新启动一下docker的&#xff0c;以重新启动其中的服务。 命令基础&#xff1a; docker images&#xff1a;查看docker中现有的镜像 docker container ls -all&#xff1a;查看docker中目前在运行的containe…

2023国赛数学建模D题思路模型代码 高教社杯

本次比赛我们将会全程更新思路模型及代码&#xff0c;大家查看文末名片获取 之前国赛相关的资料和助攻可以查看 2022数学建模国赛C题思路分析_2022国赛c题matlab_UST数模社_的博客-CSDN博客 2022国赛数学建模A题B题C题D题资料思路汇总 高教社杯_2022国赛c题matlab_UST数模社…