深度剖析进程概念与进程状态

文章目录

  • 1. 前言
  • 2. 什么是进程
    • 2.1 进程概念
    • 2.2 进程描述——PCB
  • 3. 进程的一些基本操作
    • 3.1 查看进程
    • 3.2 结束进程
    • 3.3 通过系统调用获取进程标示符
    • 3.4 通过系统调用创建子进程
  • 4. 进程状态
    • 4.1 普适的操作系统层面
    • 4.2 具体Linux操作系统层面
  • 5. 两种特殊的进程
    • 5.1 僵尸进程
    • 5.2 孤儿进程
  • 6. 进程优先级
  • 7. 进程的其他概念
  • 8. 进程切换


1. 前言

在学习上一节冯诺依曼体系结构与操作系统时,我们得出结论:管理的本质是 先描述再组织,在此基础上本篇文章将带你从以下几个方面来深入学习进程概念与进程状态:

  1. 进程是什么
  2. PCB是什么
  3. 进程的一些基本操作
  4. 进程状态
  5. 特殊的进程
  6. 进程的优先级
  7. 进程的其他概念
  8. 进程切换

2. 什么是进程

2.1 进程概念

在通常的计算机书籍或者课本中对进程概念的描述是这样的:进程就是被加载到内存中的程序,或者被运行起来的程序就叫做进程

如何理解呢?

我们知道,为了提高计算机的整体效率,在数据层面,CPU不会直接和外设打交道,而只会和内存进行交互;同样,外设也只和内存交互;我们平时编写的C/C++代码经过编译链接后形成的二进制可执行程序其实本质上就是存放在磁盘上的一个文件;所以如果我们要运行这个程序,就必须先将其加载到内存,因为CPU要从内存中读取程序中的代码和数据进行运算。

但是同时,在程序加载进内存后,操作系统要对程序进行管理,而从上一节的学习中我们知道,对程序的管理本质上是对程序数据的管理,管理的方法就是先描述,再组织

所以操作系统会从这些程序中抽象出共有的属性来构建一个结构体,然后为每一个进程都创建一个结构体的对象,最后再将所有的结构体对象使用某一种高效的数据结构组织起来。至此,对某个进程的管理就转变成了对数据结构中某一个节点的管理。在操作系统中,这个用于描述和组织进程的结构体被称为进程控制块(PCB)

2.2 进程描述——PCB

进程控制块PCB (process control block):操作系统中用于描述进程的工具,其中包含的是进程属性的集合

Linux操作系统下的PCB是task_struct,它是Linux内核的一种数据结构,其内容可以分为如下几类:

  • 标示符:描述本进程的唯一标示符,用来区别其他进程。
  • 状态:任务状态,退出代码,退出信号等。
  • 优先级:相对于其他进程的优先级。
  • 程序计数器:程序中即将被执行的下一条指令的地址。
  • 内存指针:包括程序代码和进程相关数据的指针,还有和其他进程共享的内存块的指针。
  • 上下文数据:进程执行时处理器的寄存器中的数据。
  • I/O状态信息:包括显示的I/O请求,分配给进程的I/O设备和被进程使用的文件列表。
  • 记账信息:可能包括处理器时间总和,使用的时钟数总和,时间限制,记账号等。
  • 其他信息。

抽象出来可以用如下结构体来表示(假设task_struct使用链表进行组织):

struct task_struct {     
    //进程的所有属性
    ... ...
    //进程对应的代码和数据的地址
    ... ...
    //下一个进程的地址
    struct task_struct* next;
};

注:关于task_struct的详细介绍,即其中包含的具体进程属性,可以参考这篇文章:Linux中进程控制块PCB-------task_struct结构体结构 。

当了解了task_struct之后,我们就应该从操作系统内核的观点来看待进程了:进程 = PCB + 进程对应的代码数据

3. 进程的一些基本操作

3.1 查看进程

  1. ps axj指令配合grep和管道查看指定进程:

    在这里插入图片描述

  2. /proc系统文件夹中查看所有进程:

    在这里插入图片描述

3.2 结束进程

  1. 使用Ctrl + c结束进程:

    在这里插入图片描述

  2. 使用kill -9结束进程:

    在这里插入图片描述

3.3 通过系统调用获取进程标示符

我们可以通过使用操作系统给我们提供的系统调用接口getpid()getppid()来获取进程id和父进程id(进程ID是一个进程的唯一标示):

在这里插入图片描述

注:关于函数的返回值pid_t,大家把它当作int看待即可,打印的时候也使用%d

//test.c
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>

int main()
{
    while(1)
    {
        printf("我是一个进程,我的ID是:%d,我的父进程ID是:%d\n", getpid(), getppid());
        sleep(1);
    }
    return 0;
}

在这里插入图片描述

可以看到,我们通过getpid()getppid()函数得到的值的确是我们进程对应的id。同时,我们发现test进程的父进程是bash,即shell外壳,shell为了防止自身崩溃,并不会自己去执行指令,而是会派生子进程去执行。

同一个程序重新被运行时它的进程id可能与之前不一样,因为它的代码和数据需要重新从磁盘中加载;但是它的父进程id一定是一样的,因为它们都是通过bash来执行。

3.4 通过系统调用创建子进程

我们可以通过系统调用接口 fork 来创建子进程:

在这里插入图片描述

//test.c
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>

int main()
{
    pid_t id = fork();
    if(id == 0)
    {
        while(1)
        {
            printf("子进程,pid:%d, ppid:%d, id:%d\n", getpid(), getppid(), id);
            sleep(1);
        }
    }
    else if(id > 0)
    {
        while(1)
        {
            printf("父进程,pid:%d, ppid:%d, id:%d\n", getpid(), getppid(), id);
            sleep(1);
        }
    }
    else 
    {
        printf("子进程创建失败!\n");
    }
    return 0;
}

在这里插入图片描述

可以看到,子进程的ppid是父进程的pid,父进程的ppidbash。同时,对于父进程,fork函数返回子进程的pid;对于子进程,fork返回0。

4. 进程状态

4.1 普适的操作系统层面

进程状态是什么?

一个程序被加载到内存变成进程之后,操作系统要对该进程进行管理,即为其创建对应的PCB对象。而进程状态,本质上就是PCB内部的一个整型变量,不同的整型值就对应不同的进程状态

在普适的操作系统层面,即站在操作系统学科的角度来说,进程状态可能有如下几种:运行、挂起、阻塞、新建、就绪、等待、挂机、死亡。其中最重要也是最难理解的几种状态分别是:运行、阻塞、挂起

运行状态

操作系统为了合理分配CPU以及各种硬件资源,也为了更好的调度各个进程,会为CPU创建一个进程队列,为每一个硬件都创建一个等待队列。让某一个进程处于运行状态本质上就是将该进程对应的PCB放入CPU的运行队列中排队,然后再将PCB中维护进程状态的变量修改为相应的值,比如0。

因为进程PCB里面有进程的各种属性,以及进程对应的代码和数据的地址,所以CPU从运行队列中取出PCB后,可以根据该PCB来得到进程的各种数据和指令,然后执行相应运算。

所以进程处于运行状态并不一定意味着该进程此刻正在被运行,只要该进程处于CPU的运行队列中即可。(注:CPU是纳秒级的芯片,运算速度非常快,所以只要进程处于CPU的运行队列中,我们就可以认为该进程正在被运行)

阻塞状态

和CPU一样,我们计算机中的各种硬件也是十分有限的,但是需要使用这些硬件资源的进程却有很多,比如很多进程都需要向磁盘中写入数据,又或者要通过网卡发送数据。但是一个磁盘或者一个网卡在同一个时刻只能为一个进程提供服务,那么如果此时有其他运行中的进程需要使用该硬件资源,操作系统就会将该进程的PCB放入硬件的等待队列中,等待硬件来为我提供服务。

上面这种由于访问某种硬件需要进行等待的状态就被称为阻塞状态,阻塞状态本质上就是将进程的PCB从CPU的运行队列中剥离出来,放入硬件的等待队列中,然后将PCB中维护进程状态的变量修改为相应的值,比如1。待该进程获得对应的对应的硬件资源以后,再将该进程放入CPU的运行队列中

注:并不是只有等待硬件资源进程才会处于阻塞状态,一个进程等待另一个进程就绪、一个进程等待某种软件资源就绪等都会处于阻塞状态。

挂起状态

上面我们学习了阻塞状态,处于阻塞状态的进程由于需要等待某种资源,所以它对应的代码和数据在短期内并不会被执行,此时它们仍存在在内存中就相当于浪费了内存资源。而如果当前操作系统处于高IO的情况下,内存空间不足,操作系统就会选择将这些处于阻塞状态的进程对应的代码和数据拷贝一份存放到磁盘中,然后释放内存中那一份,从而节省出内存空间

上面这种由于内存空间不足,操作系统将在等待资源的进程对应的代码数据放到磁盘中以节省内存空间的状态就被称为挂起状态挂起状态不会移动进程的PCB,只会移动进程对应的代码和数据

注:挂起进程并不是释放进程,因为该进程对应的PCB仍然处于某硬件的等待队列中,当该进程获得对应的资源以后,操作系统仍然可以将该进程对应的代码和数据从磁盘加载到内存中来继续运行,其本质是对内存数据的唤入唤出。同时阻塞不一定挂起,挂起也不一定阻塞,也可能是新建挂起、就绪挂起,甚至是运行挂起。

总结:进程状态改变的本质是进程对应的PCB (task_struct对象) 处于不同设备的运行队列/等待队列中。

4.2 具体Linux操作系统层面

上面我们谈到的都是理论上的操作系统中进程的状态,下面我们来学习具体Linux操作系统中进程的状态。

Linux内核源代码中对进程状态的定义如下:

/*
* The task state array is a strange "bitmap" of
* reasons to sleep. Thus "running" is zero, and
* you can test for combinations of others with
* simple bit tests.
*/
static const char * const task_state_array[] = {
"R (running)", /* 0 */
"S (sleeping)", /* 1 */
"D (disk sleep)", /* 2 */
"T (stopped)", /* 4 */
"t (tracing stop)", /* 8 */
"X (dead)", /* 16 */
"Z (zombie)", /* 32 */
};

可以看到,Linux中进程一共有七种状态,分别是运行、睡眠、深度睡眠 (磁盘休眠)、暂停、追踪暂停、死亡、僵尸。

运行状态(R)

运行状态即进程的PCB位于CPU的运行队列中:

在这里插入图片描述

睡眠状态(S)

Linux下的睡眠状态其实就是我们上面所说的阻塞状态,进程需要等待某种资源:

在这里插入图片描述

注:我们使用ps axj指令查看进程状态只能查看进程某一时刻的状态,而外设的速度是要远远低于CPU的,所以我们可以发现,虽然test也在执行代码,但是我们每次查询时进程基本都处于阻塞状态,因为进程99%的时间都在等待硬件资源就绪,只有1%的时间在执行打印代码。

深度睡眠状态(D)

上面我们提到,当内存空间不足的时候,操作系统会将一部分进程挂起来节省资源。但是如果内存空间严重不足,挂起已经解决不了问题的时候,操作系统就会主动杀掉某些进程。

那么这里就出现了一个问题,万一操作系统把某些非常重要的进程杀掉了怎么办?比如,当前有一个进程需要向磁盘写入一批数据,这批数据是10万名用户一年的转账记录,非常重要。该进程访问磁盘,让磁盘帮它写入数据,在磁盘写数据的时间段内,该进程是属于阻塞状态的,因为它要等待磁盘返回给它一个结果,即是否写入成功。而一旦该进程被操作系统杀掉,且恰好磁盘写入失败了,磁盘将写入结果反馈给该进程发现无人应答,磁盘就只能将该部分数据丢弃然后为其他进程提供服务。此时,这部分十分重要的用户数据就丢了。

为了防止这种情况的发生,Linux设计出了深度睡眠(D)状态,处于深度睡眠状态的进程既不能被用户杀掉,也不能被操作系统杀掉,只能通过断电,或者等待进程自己醒来。

注:深度睡眠一般只会在高IO的情况发生下,且如果操作系统中存在多个深度睡眠状态的程序,那么说明该操作系统也即将崩溃了。

暂停状态(T)

暂停状态其实也属于阻塞状态的一种,我们可以使用kill命名,指定-19选项来让一个进程从运行状态变为暂停状态:

在这里插入图片描述

在这里插入图片描述

当然,我们也可以使用kill -18让一个处于暂停状态的进程恢复运行:

在这里插入图片描述

在这里我们注意到了一个细节:我们将test暂停或者continue之后,进程状态后面的+号消失了。其实,进程状态后面的+号代表着一个进程是前台进程,没有+号就代表是后台进程。对于前台进程,我们可以使用Ctrl + c将其终止,也可以用kill命令杀死它;但是对于后台进程来说,我们只能通过kill命令来杀死它。

追踪暂停状态(t)

追踪暂停状态是一种特殊的暂停状态,进程处于此状态表示该进程正在被追踪,比如gdb调试进程:

在这里插入图片描述

死亡状态(X)

死亡状态代表着一个进程结束运行,该进程对应的PCB以及代码和数据全部被操作系统回收。

僵尸状态(Z)

我们创建一个进程的目的是为了让其帮我们完成某种任务,而既然是完成任务,进程在结束前就应该返回任务执行的结果,供父进程或者操作系统读取。

所以,一个进程在退出的时候,不能立即释放全部资源。对于进程的代码和数据,操作系统可以释放,因为该进程已经不会再被执行了,但是该进程的PCB应该保留,因为PCB中存放着该进程的各种状态代码,特别是退出状态代码。

僵尸状态就是进程在退出时等待父进程或者操作系统来读取退出状态代码,然后释放PCB的一种状态。

总结:可以看到,具体的Linux操作系统下的进程状态和普适的操作系统学科上进程的状态是不同的,比如Linux操作系统没有阻塞和挂起状态,阻塞状态通过睡眠、深度睡眠、暂停、追踪暂停等状态表现出来,而进程处于这些状态时是否会被调整为挂起状态,用户是不可得知的,因为操作系统没必要将挂起状态暴露给用户,用户也不关心一个进程是否会处于挂起状态。

5. 两种特殊的进程

5.1 僵尸进程

什么是僵尸进程?

上面我们提到一个进程的资源在被全部释放之前,需要由父进程或者操作系统来读取退出状态代码,而如果父进程不读取子进程的退出状态代码,该进程的PCB就一直得不到释放,此时该进程就会变成僵尸进程。

举个例子说明:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>

int main()
{
    int id = fork();
    if(id > 0)
    {
        while(1)
        {
            printf("我是父进程,pid: %d, ppid: %d\n", getpid(), getppid());
            sleep(1);
        }
    }
    else if(id == 0)
    {
        while(1)
        {
            printf("我是子进程,pid: %d, ppid: %d\n", getpid(), getppid());
            sleep(1);
        }
    }
    else 
    {
        perror("fork fail");
        exit(-1);
    }
    return 0;
}

在这里插入图片描述

可以看到,当我们kill掉子进程19577之后,由于父进程没有对子进程的退出状态代码进行读取,所以子进程变成了Z状态,并且子进程后面还提示了defunct(失效的,不再使用的),此时,如果父进程一直不对子进程进行读取,那么子进程就会变成僵尸进程。

僵尸进程有如下危害

如果父进程或者操作系统一直不对子进程的退出状态进行读取,那么子进程的退出状态就将一直被维持下去。维护退出状态本身就是要用数据维护,也属于进程基本信息,所以如果进程一直处于退出状态,进程对应的PCB(task_struct)就将一直存在,不会被释放,会造成内存资源的浪费

5.2 孤儿进程

什么是孤儿进程?

孤儿进程是指父进程提前退出后,子进程被操作系统领养的一种情况,被操作系统领养的进程就被称为孤儿进程。

在这里插入图片描述

在这里插入图片描述

这里还有两个细节:第一,父进程退出后并没有变成Z状态,因为父进程的父进程是bashbash会读取父进程的退出状态;第二,子进程被领养后变成了后台进程

6. 进程优先级

什么是优先级?

优先级和权限不同,权限决定的是一件事情能不能做,优先级是在权限允许的前提下,该事情先做还是后做。

为什么要有优先级?

资源是有限的,内存中有很多进程都要占用资源,但是资源是有限的,所以我们需要指定优先级来合理的分配资源。

Linux中优先级的特点:

Linux中优先级的表示与维护通过两个变量PRI(priority)NI(nice)来完成,每个进程默认的PRI都是80,NI都是0。我们可以通过修改NI的值来调整进程的优先级,NI的改动范围为[-20, 19]PRINI的和越小,进程的优先级就越高。

Linux中我们通过ps -l来查看进程的优先级:

在这里插入图片描述

我们也可以通过如下步骤来修改进程优先级(将进程优先级调高可能需要sudo权限):

输入top --> 输入r --> 输入进程id --> 输入NI值

在这里插入图片描述

最后,虽然我们可以通过修改NI值来调整进程优先级,但是我们一般都不会这样做,因为效果不大。

7. 进程的其他概念

进程还有一些其他概念:

竞争性:系统进程数目众多,而CPU资源只有少量,甚至1个,所以进程之间是具有竞争属性的。(进程为了高效完成任务,更合理竞争相关资源,便具有了优先级)
独立性:多进程运行,需要独享各种资源,多进程运行期间互不干扰。(每个进程的PCB以及代码数据都是独立的,一个进程的死亡不会影响其他进程,包括父子进程,子进程崩溃并不会影响父进程)
并行:多个进程在多个CPU下分别、同时进行运行,这称之为并行。
并发:多个进程在一个CPU下采用进程切换的方式,在一段时间之内,让多个进程都得以推进,称之为并发。(我们用的电脑一般都是并发,只有一个CPU)

8. 进程切换

我们的笔记本只有一个CPU,代表着同一时刻只能有一个进程正在被运行,但是我们平时在使用电脑的时候,同一时间通常会运行着很多程序,并且这些程序都能被正常运行,这其实是进程切换的效果。

进程切换:CPU同一时刻只能运行一个进程,但是CPU的运算速度非常快,所以位于CPU运行队列中的每一个进程都只运行一个时间片,每个进程运行完一个时间片后被都被放到运行队列尾部,等待下次运行,这样使得在一个时间段中多个进程都能被运行。

上下文保护与上下文恢复

CPU在进行进程切换时要进行上下文保护与上下文恢复:

把临时数据转存到操作系统的行为叫做上下文保护,把临时数据写回寄存器内的行为叫做上下文恢复。

我们的进程在运行时会产生非常多的临时数据,同时CPU中存在一套寄存器硬件,当进程运行时,进程的PCB会被放入CPU内的寄存器中,此时CPU就可以通过进程PCB得到进程代码数据的地址,CPU在运行进程时所产生的大量的临时数据也都会被保存在寄存器中

那么,我们在进行进程切换时需要进行进程的上下文保护与上下文恢复,即进程停止运行时将寄存器里面的数据保存起来,进程重新运行时将保存的数据再放入到寄存器中;以便我们能够接着上次运行的地方接着运行

图解:

在这里插入图片描述

注:CPU寄存器硬件被所有进程共享,但是当CPU在具体运行某一进程时,CPU寄存器中的数据只属于该进程。同时,我们进行上下文保护时保存的是寄存器中的数据,而不是寄存器硬件。

拓展学习:深入理解Linux内核进程的管理与调度


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

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

相关文章

每日OJ题_贪心算法四⑧_力扣767. 重构字符串

目录 力扣767. 重构字符串 解析代码 力扣767. 重构字符串 767. 重构字符串 难度 中等 给定一个字符串 s &#xff0c;检查是否能重新排布其中的字母&#xff0c;使得两相邻的字符不同。 返回 s 的任意可能的重新排列。若不可行&#xff0c;返回空字符串 "" 。 …

【Java基础】枚举类的方法及应用

如何实现让一个类有固定个数的对象 手动封装构造方法&#xff08;private&#xff09; → 创建静态对象 → final修饰静态对象&#xff0c;使其成为常量 class Season { //枚举类public final static Season SPRING new Season();public final static Season SUMMER new Se…

Redis的集群模式——Java全栈知识(20)

1、主从模式 Redis 支持主从模式的集群搭建&#xff0c;这是 Redis 提供的最简单的集群模式搭建方案&#xff0c;目的是解决单点服务器宕机的问题。当单点服务器发生故障的时候保证 Redis 正常运行。 主从模式主要是将集群中的 Redis 节点分为主节点和从节点。然后读和写发生在…

C++11续——智能指针(出现原因至源码模拟)

前言&#xff1a;在C11里面提出了一个新的语法 try catch用来捕捉异常&#xff0c;这样子能不使用return和exit的前提下退出程序就得到错误信息&#xff0c;但是随之而来的就是一个新的问题&#xff0c;try catch退出程序之后可能带来了无法释放的内存泄露问题&#xff0c;原因…

微信小程序 19:小程序分包

对小程序进行分包的好处主要有以下两点 可以优化小程序首次启动的下载时间在多团队共同开发时可以更好的解偶协作 分包前小程序的项目构成 分包前&#xff0c;小程序项目中所有的页面资源都被打包到一起&#xff0c;导致整个项目体积过大&#xff0c;影响小程序首次启动的下…

vue自定义权限指令

定义v-hasPermi指令 /*** v-hasPermi 操作权限处理*/import useUserStore from /store/modules/userexport default {mounted(el, binding, vnode) {const { value } bindingconst all_permission "*:*:*";const permissions useUserStore().permissions&#xff…

算法-卡尔曼滤波之基本数学的概念

1.均值 定义&#xff1a;均值是一组数据中所有数值的总和除以数据的数量。均值是数据的中心趋势的一种度量&#xff0c;通常用符号 xˉ 表示。 &#xff1a;对于包含 n 个数据的数据集 {&#x1d465;1,&#x1d465;2,...,&#x1d465;&#x1d45b;}&#xff0c;均值 xˉ 计…

常见 Web 安全攻防总结

Web 安全的对于 Web 从业人员来说是一个非常重要的课题&#xff0c;所以在这里总结一下 Web 相关的安全攻防知识&#xff0c;希望以后不要再踩雷&#xff0c;也希望对看到这篇文章的同学有所帮助。今天这边文章主要的内容就是分析几种常见的攻击的类型以及防御的方法。 也许你对…

利用CAD绘制角度斜线的简易指南---模大狮模型网

在CAD设计中&#xff0c;绘制角度斜线是常见的需求&#xff0c;尤其在工程、建筑等领域中。正确绘制角度斜线不仅可以提高图纸的清晰度和美观度&#xff0c;还有助于准确表达设计意图。本文将介绍如何利用CAD软件进行角度斜线的绘制&#xff0c;为您提供简明易懂的操作指南。 一…

什么是资源池技术?它有什么用?

在开发应用程序过程中&#xff0c;涉及到对系统资源进行有效管理时往往会用到池化操作。资源池模式的应用场景很多&#xff0c;可以管理那些想要通过重用来分摊昂贵初始化代价的对象&#xff0c;而管理数据库连接就是很好的一种应用场景。数据库连接池作为一种典型的池化技术手…

云端的艺术革命:云渲染如何重塑动画与视觉特效产业

在 2019 年&#xff0c;乔恩费儒&#xff08;Jon Favreau&#xff09;决定重拍迪士尼的经典电影《狮子王》。他的创新构想是以真实动物为模型&#xff0c;在非洲草原上拍摄&#xff0c;由真实动物“出演”的辛巴和其他角色&#xff0c;随后通过配音赋予它们生命。 为了实现这一…

vue前端时间段选择控件

实现效果: 可选具体的某天的某时某分某秒 vue前端代码: <el-form-item label"日期"><el-date-pickerv-model"daterangerq"style"width: 240px"value-format"yyyy-MM-dd HH:mm:ss"type"datetimerange"range-separat…

[笔记] srlua库编译

文章目录 前言一、环境二、编译过程2.1 gcc安装2.2 编译lua2.3 编译srlua库 三、测试srlua库参考总结 前言 一、环境 centos7.9 gcc version 4.8.5 20150623 (Red Hat 4.8.5-44) (GCC) lua5.1源码 srlua 源码 二、编译过程 2.1 gcc安装 yum install gcc这里gcc安装过程和环…

基础学习-Git(分布式版本控制系统)

学习视频推荐 http://【黑马程序员Git全套教程&#xff0c;完整的git项目管理工具教程&#xff0c;一套精通git】 https://www.bilibili.com/video/BV1MU4y1Y7h5/?p5&share_sourcecopy_web&vd_source2b85bd9be9213709642d908906c3d863 1、Git环境配置 安装Git Git下…

CAXA 3D实体设计2024:塑造未来的创新引擎

在数字化时代的浪潮中&#xff0c;3D CAD实体建模设计正成为推动工业创新的核心动力。CAXA 3D实体设计2024&#xff0c;以其卓越的性能和丰富的功能&#xff0c;为企业和个人用户带来了前所未有的设计体验。 CAXA 3D实体设计2024不仅拥有直观易用的界面&#xff0c;还配备了强…

【JS】call和 apply函数的详解

JavaScript 中 call() 和 apply() 函数的详解 在JavaScript中&#xff0c;call()和apply()都是非常重要的方法&#xff0c;用于调用函数时指定函数体内的this的值&#xff0c;从而实现不同对象之间的方法共享。尽管它们的功能非常相似&#xff0c;但在实际使用中各有其优势和特…

数据结构选择题(期末)

1.给定NN的二维数组A&#xff0c;则在不改变数组的前提下&#xff0c;查找最大元素的时间复杂度是&#xff08;A&#xff09;&#xff1a; A.O(N2) B.O(NlogN) C.O(N) D.O(N2logN) 两重循环即O(N2)的时间复杂度 2.与数据元素本身的形式、内容、相对位置、个数无关的是数据的…

OpenAI 发布新款大型语言模型 GPT-4o,带大家了解最新ChatGPT动态。

OpenAI 发布新款大型语言模型 GPT-4o 昨日OpenAI 举办了一场线上活动&#xff0c;正式发布了其最新研发的 AI 模型 GPT-4o&#xff0c;并详细介绍了该模型的强大功能和未来发展规划。此次发布标志着 AI 技术的重大突破&#xff0c;为用户提供了更加便捷、高效的 AI 工具&#…

荆州科技局副局长乔梁莅临湖北点赋网络科技公司参观调研

近日&#xff0c;荆州科技局副局长乔梁&#xff0c;莅临湖北点赋网络科技公司进行参观调研。点赋科技总经理崔梦娇亲自陪同&#xff0c;向副局长介绍了公司的D咖智能饮品机器人经营状况和研发进展情况。 在参观过程中&#xff0c;副局长乔梁对点赋科技的创新能力和技术成果给予…

【计算机毕业设计】基于SSM++jsp的高校专业信息管理系统【源码+lw+部署文档+讲解】

目录 第1章 绪论 1.1 课题背景 1.2 课题意义 1.3 研究内容 第2章 开发环境与技术 2.1 MYSQL数据库 2.2 JSP技术 2.3 SSM框架 第3章 系统分析 3.1 可行性分析 3.1.1 技术可行性 3.1.2 经济可行性 3.1.3 操作可行性 3.2 系统流程 3.2.1 操作流程 3.2.2 登录流程 3.2.3 删除信息流…