当前位置: 首页 > news >正文

【Linux进程】Linux下的---七大进程状态(什么是进程状态?Linux下有哪些进程状态?)

目录

一、前言

二、什么是进程状态?

三、操作系统(OS)下的 --- 进程状态

🔥运行状态🔥

🔥阻塞状态🔥

🔥挂起状态🔥

四、Linux下的7种进程状态

🔥运行状态 -- R🔥

🔥浅度睡眠状态 -- S🔥

🔥深度睡眠状态 -- D🔥

🔥停止状态 -- T🔥

🔥进程跟踪状态 -- t🔥  

🔥死亡状态 -- X 🔥

🔥僵死状态Z —— 两个特殊进程 🔥

① 僵尸进程

② 孤儿进程

 五、总结与提炼

 六、共勉


一、前言

        进程 只有被 操作系统(OS)管理好了,才能发挥它的全部作用,而 系统存在多个 进程操作系统(OS)无法做到面面俱到,因此为了更好的管理 进程,操作系统把 进程 分成了几种状态:运行、阻塞、挂起、休眠等等。至于每种状态的应用场景是什么?有什么用?本文将会带大家认识各种 进程 状态


在谈 进程状态 之前,我们需要了解 什么是进程怎么去描述并组织进程如何创建一个进程

  • 操作系统(OS)的本质是:先描述,在组织
  • 操作系统并非直接管理 -- 进程,而是管理 进程 的 PCB(task_struct)
  • PCB 中有着进程的各种信息,包括:PID、PPID 、进程状态
  • 我们可以通过函数 getpid()  获取当前进程的  PID
  • 进程 间存在父子关系,可以通过 fork() 主动创建 子进程
  • 父子进程 相互独立,共享一份代码时,具有 写诗拷贝 机制

如果大家还有不了解-- 进程 --的可以先看一下这篇文章:Linux 下进程的基本概念

二、什么是进程状态?

为了弄明白正在运行的进程是什么意思,我们需要知道------进程的不同状态

  • 所谓的 进程状态 其实就是 PCB(task_struct)内部的一个整形变量 ----- int status
  • 操作系统(OS)要更改一个进程状态,只要更改进程的 PCB(task_struct)中的状态属性,它只是一个标志位用来表明进程的状态,仅此而已。


那么 状态 决定了什么呢?

  • 进程后续的动作! ---- 而 操作系统(OS)中可能会存在多个进程都要根据它的状态执行后续动作,所以说明 --状态-- 对于  操作系统后续如何管理 进程十分重要!!

三、操作系统(OS)下的 --- 进程状态

  • 对于进程而言呢,它是操作系统中的概念,如果有学习过《操作系统》这门学科的话应该可以很清楚对于进程而言的话是存在着许许多多的状态,如果一开始刚刚接触的小伙伴一定会感觉这么多状态要怎么区分呀😵

  •  其实那么多的状态,真正主要的也就那么几个,所以接下去我会中重点讲解以下几种进程的状态

🔥运行状态🔥

首先我们要谈到的是【运行状态】,这个状态是最普遍的:  进程 PCB 被调度到 CPU 运行队列中且已被分配 CPU 资源,就叫做 ------ 运行状态

一个CPU,一个运行队列,也就是说这些进程都需要在CPU这里进行排队,逐个执行。

而排队的是进程么?

其实不是,排队的是进程的PCB(面试时不是你在排队,而是你的简历信息在排队)。


  • 首先对于一个进程而言,我们知道它是由 内核数据结构 + 所对应的代码和数据 所组成的,所以当系统中存在多个进程的时候就势必会存在多个结构体;当然我们需要将这些进程给链接组织起来(双向链表链接
  • 那么这些 进程 就相当于是在处在一个运行队列中,我们如果要找到这个队列中的某个进程的话,只需要找到这个进程的头部即可,那我们就可以对应地去调度某个进程,把这个进程所对应的代码和数据放到CPU上去执行


 💬 因为每个进程是需要去竞争CPU资源的,但是呢CPU不可能同时给这么多进程分配资源

  • 所以每一个CPU都会去维护一个运行队列,里面的队 头指针 head 所指向就是第一个进程所对应的【PCB】队尾指针tail 所指向就是最后一个所对应的【PCB】。所以我们要运行某一个进程只需要将 head 所指向的那个进程放到 CPU上去运行即可


提问:一个 进程 只要把自己放到 CPU 上开始运行了,是不是一直要到执行完毕,才把自己放下来?

  • 不是,每一个进程都有一个叫做:时间片的概念! 其时间大概是在10 ms左右。所以并不是一个进程一直在执行,而是这多个进程在一个时间段内所有代码都会被执行 —— 这就叫做【并发执行】 
  • 所以呢这就一定会存在大量的进程 被CPU放上去、拿下来的动作 —— 这就叫做【进程切换】 

💬 所以呢我们不要拿自己的时间感受去衡量CPU,其运行一遍速度是非常快的,你根本感受不到这种进程切换的效果 

 🔥阻塞状态🔥

 何为阻塞?

  • 阻塞 就是 进程 因等待某种条件就绪,而导致的一种不推进状态(比如等待 键盘输入)。
  • 通俗的来说 阻塞 就是 进程卡住了原因就是缺少资源

比如在我们日常生活中,常常发生堵车,原因就是道路资源不够用了,车辆这个 进程 就需要原地等待 

那么进程需要什么资源呢?

  • 比如 磁盘网卡显卡 等各种外设
  • 假设你现在想在 steam 上下载游戏,当你点击下载按钮后提示磁盘空间不足,此时是无法运行 steam下载 这个进程的,因为此 进程 需要等待足够大的 磁盘资源
  • 此时我们就称此 进程 为 阻塞 状态

 总结: 进程 阻塞 就是不被调度

  • 此时 PCB(task_struct) 就会被设置为 阻塞状态,并链入等待的资源提供的等待队列
  • 没错,这里的等待队列 类似于 CPU 运行队列 

🔥挂起状态🔥

挂起(阻塞挂起):

  • 当 CPU 资源紧张时,将 进程的数据和代码 交换至 磁盘 中挂起,此时内存中只有 PCB
     
  • 挂起 可以看作一种特殊的 -- 阻塞状态

详解:

  • 当计算机资源比较吃紧时,操作系统一定要确保自身不会因为资源的紧张而崩溃,所以就会将一些等待资源(阻塞)的进程的代码和数据交换到磁盘的 swap分区 中,这个过程称为唤出
  • 当需要调度此进程时,就会将磁盘的 swap分区 中保存的内容换回到内存中,这个过程称为唤入

注意:交换的是进程的代码和数据,不是PCB!!如果PCB被交换出内存了,那操作系统如何管理呢?

所以当某个进程的代码和数据不在内存中,而被换出到磁盘上时,该进程就为挂起状态。


思考:swap分区是越大越好么? 

磁盘本质是输入输出设备,每次唤入唤出其实都是非常低效的操作,如果swap分区设置的过大,那么操作系统就会十分依赖它,导致出现更多低效IO,这本身就是一种牺牲效率来确保操作系统能够正常运行的行为。

所以swap分区不宜设置的过大,一般为内存大小或内存大小的一半,具体要看不同的操作系统。


举个-- 挂起-- 例子 : 

在我们生活中,一边走路一边玩手机很危险,所以此时我们会将玩手机这个 进程挂起 ,即把手机揣进兜里,然后 专心执行走路这个 进程


总结: 
看了上面的三种基本的进程状态后我们可以来总结一下,如果要看进程是什么状态的话一般看这个 进程在哪里排队

  • 位于【运行队列】的话它就是处于运行状态
  • 位于【阻塞队列】的话它就是处于阻塞状态

四、Linux下的7种进程状态

        在介绍完操作系统学科下的三种最主要进程状态后,我们对进程的状态有了基本的概念,接下去就让我们正式地来学习一下 Linux 系统7种进程状态

 先来小结并回顾一下上面所学:

  1. 如果当前是运行状态,那么接下来就需要被调度运行
  2. 如果当前是阻塞状态,那就等条件就绪,等设备准备好就把当前进程投递到运行队列里,然后再被CPU调度运行
  3. 如果当前是挂起状态,要做的就是把当时换出的代码和数据重新换入,然后再把所对应的进程列入到运行队列中

以下就是关于进程的所有状态 

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 */
};

🔥运行状态 -- R🔥

 首先我们要来聊的是【运行状态R】

  • 来看下下面的这段代码,是一个死循环去 printf打印循环语句
   #include <stdio.h>#include <unistd.h>int main(void){while(1);                                                                {printf("Hello process, pid: %d\n",getpid());sleep(1);}return 0;}
  • 然后我们将下面的代码给运行起来,观察这个进程的状态时,看到其显示为 S+,不过呢读者想看到的应该是 R 才对

  • 接下去呢,我们把代码修改一下再来看看,不使用 printf打印语句了,而且直接使用一个while(1)去做循环
   #include <stdio.h>#include <unistd.h>int main(void){while(1);                                                                {//printf("Hello process, pid: %d\n",getpid());//sleep(1);}return 0;}
  • 然后我们看到,此时再运行起来时这个进程的状态就改变了,变成了 R+,这才是我们想要的【进程状态】

 💬 那有读者就要问了:为什么把 printf打印语句给去掉之后就变成这样了呢?

  • 原因就在于 printf 打印语句它是属于 IO流 的一种,第一次因为是循环的缘故,它一直在等IO设备就绪,所以其进程状态就一直为 S+,对应的即是在操作系统中的【阻塞状态】;但是当我们去掉 printf 这种IO流之后呢,它就是在纯纯运行,没有IO,那也就变成了 R 状态


 这里再补充说明一下这个  S 和 R 后面的 +

  • 这里的 R+ 代表的就是这个进程是在前台运行的,所以我们在输入任何指令后不会对其造成 任何的影响

  • 那若是我们不以正常的方式去启动这个进程的话,其进程的状态就会不一样了,可以看到我在 ./mytest 的后面加上了一个 &;那么其状态变成了 R,此代表的意思就是这个进程它是运行在了【后台】的

  •  不过呢,R状态并不代表这个进程就在运行,而代表其在运行队列中排队而已.

总结:
          "+"代表是前台运行,无"+"代表后台运行,后台运行时可在命令行继续输入指令并执行,但无法用ctrl+c结束,需要用kill -9 pid杀死。想要后台运行某个程序就在后面加"&",如:./test &


 🔥浅度睡眠状态 -- S🔥

 接下去我们再来介绍一下Linux下的睡眠状态S

  • 我们再通过一段代码来看看
   #include <stdio.h>#include <unistd.h>int main(void){int a = 0;printf("Enter# ");scanf("%d", &a);printf("echo : %d\n", a);return 0;                                                                         } 
  • 将该进程运行起来我们可以看到其是出于 S+ 的状态,因为【shell】此时正在等待用户的输入,这个就对应到了我们上面所讲到的 阻塞状态


 🔥深度睡眠状态 -- D🔥

 除了【浅度睡眠】之外呢,还有一种叫做【深度睡眠】,它们俩呢,都是 阻塞状态

  • 对于浅度睡眠来说,之所以称为 “浅度”,是有原因的:也就是处于这种状态的进程容易被唤醒。例如说我们在上面所讲到的这个处于阻塞状态的进程,我们使用 kill -9 PID 向这个进程发送【9号信号】,那么这个进程就被杀死了,你也可以认为被唤醒了

 好,接下去呢我就通过一个故事📖来描述一下这个【深度睡眠】到底是怎样一种状态

  • 深度睡眠状态/不可中断睡眠状态/磁盘休眠状态,顾名思义,在这个状态的进程不会被杀掉,哪怕是操作系统也不行,通常会等待IO的结束。
  • 例如,某一进程要求对磁盘进行写入操作,那么在磁盘进行写入期间,该进程就处于深度睡眠状态,是不会被杀掉的,因为该进程需要等待磁盘的回复(是否写入成功)以做出相应的应答。
  • 如果在这个过程中,操作系统能够杀死该进程,那么就有可能丢失数据。

🔥停止状态 -- T🔥

好,接下去呢我们来讲讲【停止状态T

  • 首先我们要通过下面这句命令来查看一下对应的进程信号
kill -l
  • 此处我们要使用到的是18、19号信号

  • 接下去我们就来试一试如何让这个进程暂停之后又重新启动会是怎样的
#include <stdio.h>
#include <unistd.h>int main()
{while(1){printf("hello my process: %d\n",getpid());sleep(1);                                                                                       }return 0;}


 所以我们来总结一下

  • 暂停进程
kill -19 PID
  • 启动进程
kill -18 PID

💬 所以呢,如果我们要将一个进程给终止的话,发送19号信号即可,要让其继续启动起来,则发起18号信号 


那我现在要问了,这个 T停止状态S睡眠状态 有什么不同呢?

  1. stopped状态 进程 完全暂停了, 其不会再接收任何信号了
  2. 一个进程通过 stopped 状态可以控制另一个
  3. S 和 D 一定是在等待某种资源,而 T状态 可能在等待某种资源,也可能被其他进程控制

🔥进程跟踪状态 -- t🔥  

 接下去呢,我们再来说说进程的跟踪状态t,还记得我们在基础篇中所学习的 GDB 调试 吗?

  • 首先我们在正常状态下查看这个进程的状态,其为 S睡眠状态。接下去呢我进行了【gdb】调试,在行内打上断点后,输入 运行起来后,我们再去查看这个进程的状态时,就发现其状态变成了t原因就在于这个进程在调试的时候停了下来


🔥死亡状态 -- X 🔥

对于【死亡状态X】来说呢,这个状态只是一个返回状态,你不会在任务列表里看到这个状态🙅‍ 

  • 第一种方法就是向这个进程发送9号信号,就可以杀掉这个进程
kill -9 PID

  • 第二种方法就是通过这个进程的名称来杀掉它
killall 进程名


🔥僵死状态Z —— 两个特殊进程 🔥

接下去我们来介绍一种状态叫做【僵死状态Z】,对于这个状态,我们要涉及到两个特殊的进程叫做 僵尸进程 与 孤儿进程 

① 僵尸进程

 首先我们要来介绍的是僵尸进程,这里呢通过一个故事来进行引入

  • 你呢,很喜欢晨跑🏃‍,这一天早晨6点又起来跑步了,当你路过一个公园的时候,遇到了一个晨练的【程序员】,边跑边掉头发😀 但是呢,跑着跑着,此时突然他就“啪叽”倒了下来。那你此时就非常担惊受怕了,马上拨打了110和120的电话,然后守在他的身边等待救援来到,周边的人看到也都纷纷围了过来,其中不免有一些人会紧急救援。不过等了一会这个人就没了呼吸🖤

  • 过了十几分钟后,救护车和警车都来了,警察先封锁了,让法医过来检验一下其状况,就说:“这个人已经没救了,赶紧通知家属准备后事吧~。”


好,我们回归正题,来说说这个【僵尸进程】 

  • 因为在救护车来之前这个人其实就已经死亡了,但是其状态还没有被检测,当前并不知道它的死因,所以我们操作系统就可能会维护当前的这个状态,这个状态即为Z状态,即[僵死状态]

 💬 那我现在想问了:有一个进程暂时退出了,它要将它的状态暂时维持一段时间,问题是它维持给谁看呢?

  •  答:父进程!当一个进程退出的时候,那最关心它的便是【父进程】。因为这个父进程费了很大的劲才将这个子进程 fork 出来,此时呢它突然挂掉了,那么此时父进程就必须去关心一下对应的子进程退出时的原因

就上面这样生冷的文字来叙述还不太行,接下去我们通过实际的案例来观察一下🔍

    #include <stdio.h>2 #include <unistd.h>3 #include <stdlib.h>4 #include <sys/types.h>5 6 int Test1()7 {    8   pid_t id = fork();    9   if(id < 0)    10   {          11     //创建失败                                                                                         12     printf("创建fork失败!\n");13     return 1;           14   }                                 15   else if(id == 0)                16   {                                   17     //子进程暂停3s后终止18       printf("I'm child process, ");19       printf("pid:%d ", getpid());20       printf("ppid:%d \n", getppid());21       sleep(3);       22     return 0;23   }  24   else{                               25     //父进程死循环                 26     while(1)                          27     {          28       printf("I'am parent process, ");29       printf("pid: %d ", getpid());30       printf("ppid: %d\n", getppid());31       sleep(1);32     }33     return 0;34   }35 }36           37  38           39            40 int main()41 {42   Test1();43   return 0;44 }                    
  • 运行起来可以看到,在一开始的 3s 内,父子进程还是同时在跑的,但是当子进程在循环结束后退出了。不过此时呢父进程还在运行并没有退出。所以我们在右侧查看这两个进程的状态时间就发生了一定的变化

  • 仔细地来看一下这个状态的变化,其中【PID】为 2815,其父进程为 2814,一开始它们均为S 睡眠状态,但是呢到了后面子进程的状态就变成了Z僵死状态。也就意味着此时子进程已经死亡了,但是呢父进程还不知道
  • 这里还可以通过右侧的这个<defunct>这个来看,它表示【失效的、不再存在的

所以我们总结一下: 

💬 进程一般退出的时候,一般其不会立即彻底退出。如果父进程没有主动回收子进程信息,子进程会一直让自己处于Z状态,这也是为了方便后续父进程读取子进程的相关退出结果。 

那对于上面的这种子进程,我们就将其称作为是【僵尸进程】,不过呢这种进程是存在一定危害的!

  • 那一个父进程创建了很多子进程,就是不回收,是不是就会造成内存资源的浪费?是的!因为数据结构对象本身就要占用内存,想想C中定义一个结构体变量(对象),是要在内存的某个位置进行开辟空间
  • 那么对于上面的这种危害我们就称作为是【内存泄漏】,要如何去进行避免呢,之后的文章会做讲解~ 

 ② 孤儿进程

  • 上面我们讲到,当一个子进程突然退出但是父进程并没有去主动回收的话,那么此时这个子进程就会变成【僵尸进程
  • 那看到下面我们将这个进程突然终止之后,父子进程都不见了

💬 那此时我想问:这个父进程突然之间退出了,但是呢它的父进程并不知晓,那为何这个父进程没有处于【僵尸状态Z】呢? 

因为当前这个进程是 bash 的子进程,当其一退出之后,bash 就将其回收了。可是这个子进程为什么也没了呢?这个的话我们就要聊聊【孤儿进程】了 


接下去我们来将上面测试僵尸进程的代码做个修改,让父进程先于子进程退出 

    #include <stdio.h>2 #include <unistd.h>3 #include <stdlib.h>4 #include <sys/types.h>5 6 int Test1()7 {8   pid_t id = fork();9   if(id < 0)10   {11     //创建失败                                                                           12     printf("创建fork失败!\n");13     return 1;14   }15   else if(id == 0)16   {17     //子进程进入死循环18     while(1)19     {20       printf("I'm child process, ");21       printf("pid:%d ", getpid());22       printf("ppid:%d \n", getppid());23       sleep(1);24     }25     return 0;26   }27   else{28     //父进程暂停3s后终止    29       printf("I'am parent process, ");30       printf("pid: %d ", getpid());31       printf("ppid: %d\n", getppid());32       sleep(3);                                                                  33     return 0;34   }35 }36 37 38 39 40 int main()41 {42   Test1();43   return 0;44 }
  • 然后通过进程状态追踪来看看,我们观察到一开始两个父进程和子进程是同步在走的,但是呢过了一会父进程终止了,只有子进程还在跑,此时我们需要留意的不是其进程状态,而是这个子进程的 PPID 即父进程的 PID,它由原先的【22677】变成了【1】,这是为什么呢?

  • 这里的话就要给读者普及一下了,对于PID的值为1的进程,我们一般将其称作为是【系统进程】。我们可以使用下面这句指令去查找一下
ps ajx | head -1 && ps ajx | grep systemd
  • 然后我们看到这个【系统进程】的PID即为1

 那为何会出现上面这种现象呢?是这个子进程突然换父进程了吗?

  •  对于父子进程来说,如果父进程先于子进程结束的话,那么这个子进程就会被称作为是【孤儿进程】,对于孤儿进程来说呢,它会有1号进程即【系统进程】所领养,因为此时这个进程没有了父进程了,所以需要有人去带领它 

 💬 但是这个孤儿进程为什么要被领养呢?

  • 其实很简单,既然它是一个进程的话,最终都是要退出的,但是没了父亲的话就只能由系统进程来进行维护了

 五、总结与提炼

最后来总结一下本文所学习的内容📖 

在本文中,我们主要讲解了两个大点,一个是在操作系统中所常见的一些进程状态,它们分别为:运行状态、阻塞状态、挂起状态 

  • 所被调度的、处于运行队列里的这些进程所处的状态我们称之为 运行状态R
  • 处于等待队列中,同时在等待外设相应的进程所处的状态我们称之为 阻塞状态R
  • 当把一个进程的 数据和代码都重新交换到外设当中,进程所处的状态我们称之为 挂起状态R

接下去我们又介绍了在Linux系统下的七种进程状态,分别是:运行状态R、浅度睡眠状态S、深度睡眠状态D、停止状态T、进程跟踪状态t、死亡状态X、僵死状态Z

  • 当一个进程没有在等待IO流的时候,其就会处于 运行状态R
  • 使用 sleep() 函数可以很好地使一个进程处于浅度睡眠状态S
  • 如果不想让一个进程在等待磁盘操作的时候被操作系统杀掉,则可让其处于 深度睡眠状态D
  • 可以向一个进程发送【19】号信号使其暂停,处于停止状态T继续发送【18】号信号的话则可以使其重新启动
  • 在【gdb】的环境下去运行一个断点的话则可以使其处于进程跟踪状态t
  • 使用kill -9 PID就可以杀掉一个进程,使其处于死亡状态X
  • 如果让一个子进程在父进程不知晓的时候退出,那么其就会处于僵死状态Z,变为【僵尸进程】;若是在父子进程中父进程先于子进程退出的话,那么这个子进程就会变成【孤儿进程

 六、共勉

        以下就是我对【Linux系统编程】Linux下的七大进程状态 的理解,如果有不懂和发现问题的小伙伴,请在评论区说出来哦,同时我还会继续更新【Linux系统编程】请持续关注我哦!!! 

相关文章:

【Linux进程】Linux下的---七大进程状态(什么是进程状态?Linux下有哪些进程状态?)

目录 一、前言 二、什么是进程状态&#xff1f; 三、操作系统(OS)下的 --- 进程状态 &#x1f525;运行状态&#x1f525; &#x1f525;阻塞状态&#x1f525; &#x1f525;挂起状态&#x1f525; 四、Linux下的7种进程状态 &#x1f525;运行状态 -- R&#x1f525;…...

Linux的dev/ 和 sys/ 和 proc/ 目录

linux精神&#xff1a; 一切设备皆文件。 设备被抽象成文件 1、 /dev : 该目录放的设备文件&#xff0c;是应用程序和内核的交互文件&#xff0c;应用程序对这些文件的读写控制可以直接访问到实际的设备 应用程序通过mknod创建的文件&#xff0c;如果底层驱动对mknod的设备号…...

代码随想录算法训练营day64 | 98. 所有可达路径

图论理论基础 1、图的种类 整体上一般分为 有向图 和 无向图。 加权有向图&#xff0c;就是图中边是有权值的&#xff0c;加权无向图也是同理。 2、度 无向图中有几条边连接该节点&#xff0c;该节点就有几度 在有向图中&#xff0c;每个节点有出度和入度。出度&#xff…...

php上传zip压缩包到服务器并解压,解析压缩包内excel表格数据导入到数据库

需求: 1.需要管理后台将excel表格中的每条单词数据导入到数据库中. 2.每条单词数据对应的图片和音频文件需要上传到服务器中. 为了让客户上传数据方便,考虑了一下决定通过后台上传压缩包的方式实现 测试压缩包: 压缩包的目录结构 管理后台导入教材 public function upload…...

48-5 内网渗透 - JuicyPotato、Pipe Potato提权

Juicy Potato Juicy Potato 与 Rotten Potato(烂土豆) 的原理几乎完全相同,只是在后者的基础上做了扩展,以便更灵活地利用 Rotten Potato。Juicy Potato 不再像 Rotten Potato 那样依赖于一个现有的 Meterpreter,并且可以自定义 COM 对象加载的端口,以及根据系统版本更换…...

Windows C++ 应用软件开发从入门到精通详解

目录 1、引言 2、IDE 开发环境介绍 2.1、Visual Studio 2.2、Qt Creator 3、 C语言特性 3.1、熟悉泛型编程 3.2、了解C/C异常处理 3.3、熟练使用STL容器 3.4、熟悉C11新特性 4、Windows 平台的编程技术与调试技能 4.1、需要掌握的若干编程技术和基础知识 4.2、需…...

Leetcode 3195. Find the Minimum Area to Cover All Ones I

Leetcode 3195. Find the Minimum Area to Cover All Ones I 1. 解题思路2. 代码实现 题目链接&#xff1a;3195. Find the Minimum Area to Cover All Ones I 1. 解题思路 这一题还是挺简单的&#xff0c;只要找到所有1所在的元素的上下左右4个边界&#xff0c;作为目标矩形…...

ONLYOFFICE8.1版本桌面编辑器测评

目录 一、引言 二、界面设计&#xff1a;简洁大方&#xff0c;操作便捷 三、功能评测&#xff1a;全面升级&#xff0c;满足多样需求 四、性能评测&#xff1a;稳定流畅&#xff0c;高效运行 五、总结与展望 ONLYOFFICE官网链接&#xff1a;ONLYOFFICE - 企业在线办公应用…...

线性代数|机器学习-P15矩阵A的低秩变换下的逆矩阵

文章目录 1. 单位矩阵的秩1变换1.1 功能说明1.2 证明 2. 单位矩阵 I n I_n In​的秩k变换3. 一般矩阵A的秩k变换4. 公式用途4.1 求解方程4.2 卡曼滤波 1. 单位矩阵的秩1变换 1.1 功能说明 假设我们有一个单位矩阵I&#xff0c;列向量u,v那么当我们对单位向量I减去秩为1的矩阵…...

强强联合 极光推送(JPush)成为华为生态市场首家推送类SDK服务商

近日&#xff0c;中国领先的客户互动和营销科技服务商&#xff0c;极光&#xff08;Aurora Mobile&#xff0c;纳斯达克股票代码&#xff1a;JG&#xff09;的核心产品极光推送&#xff08;JPush&#xff09;顺利通过华为开发者联盟的多项测试及审核&#xff0c;成为首家在Harm…...

防止在 Qt 中触发信号

在 Qt 中工作时&#xff0c;有时我们需要暂时阻止某些信号的触发。以下是一个经典场景&#xff1a;我们有一个 QCheckBox 对象&#xff0c;当用户勾选或取消勾选时&#xff0c;需要调用一个函数&#xff0c;因此我们将这个函数连接到 stateChanged(int state) 信号。然而&#…...

【UML用户指南】-17-对基本行为建模-交互

目录 1、消息的可视化表示 2、对象与角色 3、链和连接件 4、消息 5、序列 6、创建、修改和撤销 7、表示法 8、常用建模技术 8.1、对控制流建模 8.1.1、基于时间的控制流 8.1.2、基于结构的控制流 在任何有意义的系统中&#xff0c;对象都不是孤立存在的&#xff0c;…...

Java中的类加载器与热部署技术详解

Java中的类加载器与热部署技术详解 大家好&#xff0c;我是免费搭建查券返利机器人省钱赚佣金就用微赚淘客系统3.0的小编&#xff0c;也是冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01;在软件开发中&#xff0c;特别是在大型应用和服务的开发过程中&#xff0c;类…...

【事件总线】EventBus

文章目录 概述如何使用如何发布消息如何进行消息监听 来源 概述 事件总线是对发布-订阅模式&#xff08;观察者&#xff09;的一种实现&#xff0c;是一种集中式事件处理机制&#xff0c;允许不同的组件之间进行彼此通信而又不需要相互依赖&#xff0c;达到一种解耦的目的。 …...

LeetCode 热题100 --双指针

双指针 b站UP主蜜糖&#xff1a;由于数据特征的有序性&#xff08;大小或者正负&#xff09;&#xff0c;所以可以证明当前节点一定是优于过往节点&#xff0c;从而可以通过数据的维度数量的指针&#xff0c;逐步的迭代收敛最终找到最优解。 283.移动零 相关标签 &#xff1a;…...

从《深入设计模式》一书中学到的编程智慧

软件设计原则 优秀设计的特征 在开始学习实际的模式前&#xff0c;让我们来看看软件架构的设计过程&#xff0c;了解一下需要达成目标与需要尽量避免的陷阱。 代码复用 无论是开发何种软件产品&#xff0c;成本和时间都最重要的两个维度。较短的开发时间意味着可比竞争对…...

Redis 基本配置

Redis的配置文件通常位于 /etc/redis/redis.conf。以下是一些常见的Redis配置选项和它们的说明&#xff1a; 基本配置 1. 绑定地址 bind 127.0.0.1默认情况下&#xff0c;Redis只监听本地接口。如果需要远程访问&#xff0c;可以修改成bind 0.0.0.0&#xff0c;不过这会带来…...

【C++庖丁解牛】函数栈帧的创建与销毁

&#x1f341;你好&#xff0c;我是 RO-BERRY &#x1f4d7; 致力于C、C、数据结构、TCP/IP、数据库等等一系列知识 &#x1f384;感谢你的陪伴与支持 &#xff0c;故事既有了开头&#xff0c;就要画上一个完美的句号&#xff0c;让我们一起加油 目录 1. 寄存器2. ebp和esp是如…...

Java基础16(集合框架 List ArrayList容器类 ArrayList底层源码解析及扩容机制)

目录 一、什么是集合&#xff1f; 二、集合接口 三、List集合 四、ArrayList容器类 1. 常用方法 1.1 增加 1.2 查找 int size() E get(int index) int indexOf(Object c) boolean contains(Object c) boolean isEmpty() List SubList(int fromindex,int …...

数组:移除元素

参考资料&#xff1a;代码随想录 本题思路&#xff1a;通过快慢指针将两次循环减少到一次 class Solution {public int removeElement(int[] nums, int val) {//0 1 2 2 2 2 3int fast 0;int slow 0;while(fast < nums.length){if(nums[fast] ! val){nums[slow] nums[f…...

胡说八道(24.6.22)——通信杂谈(完结)

上回书说到雷达和香农的信息论&#xff0c;今天来进行完结。 数字幅值调制或幅值键控&#xff08;ASK&#xff09;调制方式是指载波信号的幅值随数字基带信号而变化&#xff0c;因此可以实现将基带信号搬移到载波频段。2ASK是利用代表数字信息0或1的基带矩形脉冲去键控一个连续…...

设计模式原则——里氏替换原则

设计模式原则 设计模式示例代码库地址&#xff1a; https://gitee.com/Jasonpupil/designPatterns 里氏替换原则 继承必须确保父类所拥有的性质在子类中依然成立 与开闭原则不同的是开闭原则可以改变父类原有的功能&#xff0c;里氏替换原则不能修改父类的原有的性质&#…...

详解 ClickHouse 的 SQL 操作

传统关系型数据库&#xff08;以 MySQL 为例&#xff09;的 SQL 语句&#xff0c;ClickHouse 基本都支持 一、插入 --语法&#xff1a; insert into table_name values(xxxxxx),(yyyyyyy),...;insert into table_name select xxxxx from table_name2 where yyyyy;二、更新和删…...

WPF与Winform,你的选择是?

概述 在桌面应用的发展历程中&#xff0c;Winform和WPF作为微软推出的两大框架&#xff0c;各自承载着不同的设计理念和技术特色。Winform以其稳定、成熟的技术基础&#xff0c;长期占据着企业级应用开发的重要地位。而WPF&#xff0c;作为后来者&#xff0c;以其现代化的UI设计…...

基于SpringBoot的实习管理系统设计与实现

你好呀&#xff0c;我是计算机学姐码农小野&#xff01;如果有相关需求&#xff0c;可以私信联系我。 开发语言&#xff1a; Java 数据库&#xff1a; MySQL 技术&#xff1a; SpringBoot框架&#xff0c;B/S模式 工具&#xff1a; MyEclipse&#xff0c;Tomcat 系统展示 …...

编程用什么电脑不卡的:深度解析与推荐

编程用什么电脑不卡的&#xff1a;深度解析与推荐 在编程的世界里&#xff0c;一台流畅不卡的电脑无疑是每个开发者的得力助手。然而&#xff0c;面对市场上琳琅满目的电脑品牌和型号&#xff0c;如何选择一台适合编程的电脑却成为了一个令人困惑的问题。本文将从四个方面、五…...

优先级队列模拟实现

目录 1.堆的概念 2.堆性质堆中的某个元素小于或大于他的左右孩子 3.小根堆实例 4.堆创建 4.1调整思路 4.2向下调整思路 4.3代码实现&#xff08;大根堆&#xff09; 5.堆的删除 6.堆的插入 7.常用接口 7.1PriorityQueue和PriorityBlockingQueue 1.堆的概念 如果有一…...

记一次服务器崩溃事件

今天在安装Jenkins的时候&#xff0c;进行到插件安装这一步&#xff0c;本来一切顺利&#xff0c;结果最后安装完成之后一直进不去网页&#xff0c;显示连接超时&#xff0c;网上搜索了一圈也没发现什么相似的情况&#xff0c;当我疑惑的时候回到Linux控制台&#xff0c;发现命…...

神经网络 #数据挖掘 #Python

神经网络是一种受生物神经元系统启发的人工计算模型&#xff0c;用于模仿人脑的学习和决策过程。它由大量互相连接的节点&#xff08;称为神经元&#xff09;组成&#xff0c;这些节点处理和传递信息。神经网络通常包含输入层、隐藏层&#xff08;可有多个&#xff09;和输出层…...

营销复盘秘籍,6步法让你的活动效果翻倍

在营销的世界中&#xff0c;每一次活动都是一次探险&#xff0c;而复盘就是探险后的宝藏图&#xff0c;指引我们发现问题、提炼经验、优化策略。 想要学习如何复盘&#xff0c;只要了解以下复盘六大步骤&#xff0c;即可不断总结&#xff0c;逐渐走向卓越。 第一步&#xff1…...