【Linux】深刻理解进程概念、进程状态、进程常用指令和系统调用

news2025/8/16 16:59:34

文章目录

    • 1、什么是进程?
      • 1.1 PCB的概念
      • 1.2 程序加载到内存
    • 2、初识进程
      • 2.1 进程相关的指令
      • 2.2 进程相关的系统调用
    • 3、进程状态
      • 3.1 运行、阻塞和挂起状态
      • 3.2 具体的Linux进程状态
      • 3.3 僵尸进程
      • 3.4 孤儿进程

1、什么是进程?

从程序说起,我们写好的程序在经过编译链接最后生成的可执行文件是在磁盘上放着的。

当我们运行它的时候,程序加载到内存。

操作系统对内存里的数据进行管理,如果有很多个程序加载到内存,这些程序作为写到内存里的软件,操作系统就需要管理这些软件,那么操作系统该如何管理呢?
先描述,再组织。

1.1 PCB的概念


为了管理这么多的程序,操作系统将其描述,就有了进程控制块(PCB),说白了就是定义一个结构体。

操作系统为每个程序生成对应的进程控制块,里面包括了程序的各种属性,对应的代码和属性地址,以及可能有下一个进程控制块的指针。

struct task_struct
{
	//该进程的属性
	//比如:进程ID、进程状态、优先级等
	
	//该进程对应的代码和属性地址
	
	struct task_struct* next;
}

这些在原来的可执行文件中是没有的,可执行文件中只有代码和数据

1.2 程序加载到内存


当程序中的代码和数据加载到内存后,操作系统会针对每一个程序匹配一个进程控制块,说白了就是一个结构体变量。

struct task_struct* p1 = malloc(struct task_struct);
//并且加载好对应的属性信息
p1->.. = xx
p1->addr = 代码的地址


为了方便,结构体变量可以通过next链接起来,当CPU想要调度一个进程的时候,操作系统就可以直接通过PCB对进程进行对应的操作。

所谓的对进程管理,变成了对进程对应的PCB进行管理,转换成对链表的增删查改。(比如一个进程死亡了,操作系统就可以通过查找到对应的PCB,再将对应加载到内存的可执行文件删除。)

在这里插入图片描述

总结:
进程 = 内核数据结构(task_struct)+ 进程对应的磁盘代码。


2、初识进程

当我们写好的程序,在编译后形成的可执行文件没有运行时并不是一个进程!
process未运行时,本身不能作为一个进程。
在这里插入图片描述

当程序运行,程序加载到内存中,这时才能称为进程,那么我们在Linux如何查看进程呢?


2.1 进程相关的指令

ps ajx 查看当前所有进程

ps ajx | grep process 通过配合grep获取对应进程,比如这里的process

配合 ps ajx | head -1 可以显示相关的标题

比如: 我们要查看process进程相关信息
ps ajx | head -1 && ps ajx | grep process | grep -v grep 获取process进程信息,显示标题,忽略grep相关进程信息

在这里插入图片描述
在上述标题中:

  1. PPID:代表父进程ID
  2. PID:该进程ID
  3. PGID:该进程的组ID
  4. SID:会话ID
  5. TTY:对应的终端
  6. STAT:状态
  7. UID:用户ID
  8. COMMAND:哪一个进程


  • kill 命令

通过 kill -l 查看kill 相关的所有信号
在这里插入图片描述

通过 kill -9 进程ID 通过9号信号和相应进程PID,可以杀死对应进程

当进程正在运行时
通过 kill -19 进程ID 可以暂停进程
通过 kill -18 进程ID 可以继续进程


2.2 进程相关的系统调用

系统调用是操作系统为用户提供的接口,我们可以在程序中试试这些接口。

getpid() 返回子进程PID
getppid() 返回父进程PID
在这里插入图片描述


  • getpid()

通过持续运行一个简单的程序,让我们在Linux中找到它。

  1 #include <stdio.h>
  2 #include <unistd.h>
  3 
  4 int main()
  5 {
  6     while(1)
  7     {
  8         printf("我是一个进程,对应PID: %d\n", getpid());
  9 
 10         sleep(3);                                                                                                                               
 11     }
 12     return 0;
 13 }

在这里插入图片描述

程序运行后,通过访问linux的/proc目录,我们看到目录下有一个和进程PID匹配的文件,其实进程本身就是一个文件,该文件保存着进程的各种属性。
在这里插入图片描述

我们通过访问16005文件,可以看到其中exe就记录了操作系统在哪加载的路径。
在这里插入图片描述

一旦程序运行结束,或者杀死进程,这些也就消失了。


  • getppid()
  1 #include <stdio.h>
  2 #include <unistd.h>
  3 
  4 int main()
  5 {
  6     while(1)
  7     {
  8         printf("我是一个进程,对应PID: %d, PPID: %d\n", getpid(), getppid());                                                                   
  9                                                                                                   
 10         sleep(3);                                                                                 
 11     }                                                                                             
 12     return 0;                                                    
 13 }

在这里插入图片描述

在这里插入图片描述

通过命令查看进程,我们只看下两行,子进程PID对应没问题,值得注意的是父进程PPID
20825,对应的就是bash,bash对应的就是我们的shell,所以我们也知道shell本身也就是个进程。

命令行上启动的进程,一般它的父进程没有特殊情况的话,都是bash。
如果kill -9 20825,我们这整个shell就寄了,就需要重启恢复了。


我们重新启动程序,发现子进程PID变了,而父进程PPID依旧是20825。

在这里插入图片描述

我们的程序在运行后,其实就是shell的一个子进程,这个进程在这次结束后,再次运行,可能之前对应的PID就被其它进程继承了。(相当于医院挂号,如果你退出队列就可能需要重新挂号了)


那么为什么shell要创建子进程呢?
通过一个小程序理解一下

1 #include<stdio.h>
2 #include <unistd.h>
3 
4 int main()                                                                                                                                    
5 {         
6     while(1)
7     {       
8         printf("我是一个进程!, 我的ID是: %d, 父进程pid: %d\n", getpid(), getppid());
9         sleep(1);                                                                   
10        int a = 1/0;
11     }               
12     return 0;
13 }

通过运行,由于1/0的错误,命令行上启动的子进程终止,但这并不会影响bash,也就是说子进程的崩溃,不影响其父进程

在这里插入图片描述
在这里插入图片描述

换句话来说,shell创建子进程,就是为了不影响父进程。
(就相当,你得去完成一件事,但是你不想因为做错这一件事背锅,所以你找了一个背锅的)


  • 初识 fork()调用创建子进程

在这里插入图片描述

fork函数是一个系统调用,在当前进程下创建子进程,在被调用前只有一个父进程(当前程序),在调用后有一个父进程和一个子进程(新的进程)。


我们先来看功能:

  1 #include <stdio.h>
  2 #include <unistd.h>
  3 
  4 int main()
  5 {
  6     fork();
  7                                                                                                                                                 
  8     printf("进程 PID: %d, PPID: %d\n", getpid(), getppid());
  9 
 10     sleep(2);
 11 	return 0;
 12 }

前面说到,fork在调用之前只有一个父进程,在调用后又多了一个子进程,所以结果打印了两句才是我们要的结果。

在这里插入图片描述
结果没问题。


  • fork的返回值

父进程返回子进程PID,子进程返回0。

  1 #include <stdio.h>  
  2 #include <unistd.h>  
  3   
  4 int main()  
  5 {  
  6     pid_t id = fork();  
  7     while(1)  
  8     {   
  9         if(id < 0)
 10         {
 11             printf("fork error!\n");                                                                                                            
 12         }                                                                                                                         
 13         if(id > 0)                                                                                                                
 14         {                                                                                                                         
 15             printf("父进程PID: %d, PPID: %d id: %d \n", getpid(), getppid(), id);                                                            
 16             sleep(2);                                                                                                             
 17         }                                                                                                                         
 18         else                                                                                                                      
 19         {                                                                                                                         
 20             printf("子进程PID: %d, PPID: %d id: %d \n", getpid(), getppid(), id);                                                            
 21             sleep(2);                                                                                                             
 22         }                                                                                                                         
 23     }                                                                                                                             
 24     return 0;                                                                                                                     
 25 }

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

从结果来看,在fork调用之前,进程21788执行代码,在fork调用之后,创建子进程,会有父进程+子进程两个进程在执行后续代码,后续代码被两个进程共享。

对于返回值,进程在执行fork后创建子进程,并且返回子进程的PID,创建的子进程调用fork返回0,通过返回值不同,让父子进程执行后续共享代码的一部分!


3、进程状态

我们可能听过很多进程状态,比如:运行、挂起、等待、阻塞、挂机、死亡等,
进程的这么多状态,其实就是为了满足不同的运行场景的!
下面通过操作系统层面,理解一些重要的状态!


3.1 运行、阻塞和挂起状态

  • 操作系统对硬件和进程的管理

根据操作系统对硬件的管理(感性认知操作系统),我们得知操作系统需要对硬件进行管理。操作系统对每一个硬件都在内部加载了对应的结构体,里面有着硬件的各种属性,方便操作系统了解硬件的各种情况。

对于磁盘中的可执行程序,在加载到内存中,操作系统为了管理对应进程就有了对应的进程控制块。
在这里插入图片描述
根据冯诺依曼体系,上述结构体都在内存当中,因为操作系统在开机之后加载到了内存里。

  • 运行状态

如果当前进程想在CPU中运行,这时CPU就会为操作系统维护一个队列,这个队列其实就是为进程运行进行管理的(进程队列或进程排队)。

假设只有一个CPU,而一个CPU对应一个运行队列。
让一个进程进入CPU运行,就是让这个进程进队列,本质就是将该进程的task_struct 结构体对象放入队列中。(就相当于公司在面试时,在筛选简历后,是根据每个人正在排队的简历进行"运行")。

凡是在运行队列中的进程,它的状态都是运行状态(R状态)!
(不止是在CPU中跑,只要在队列里都算运行状态)
在这里插入图片描述


状态是什么?

状态其实就是进程的一种内部属性,进程的属性由进程控制块记录,而在进程控制块中其实就是数字
int ( 1 : run(运行),2:stop(中止),3:hup(挂起),4:dead(死亡)…)

  • 阻塞状态

根据冯诺依曼体系,CPU很快,相较于CPU外设很慢。

CPU运行进程时,可能你写的代码中需要对硬件进行访问(比如读写文件),所以进程或多或少都要访问硬件,而硬件不仅慢也是少量的,再者访问硬件的可能有很多进程(比如网卡需要对多个进程访问)。

当有个进程A正在访问磁盘,而进程B和C也需要访问磁盘,这时BC进程就需要等待!

所以不要以为,进程只会等待(占用)CPU资源,你的进程,也可能随时随地需要外设资源!

其实每个硬件在操作系统对应的结构体都会有自己的等待队列(wait_queue)。

当CPU在运行一个进程,这个进程需要访问磁盘,同时磁盘也正在被其它进程访问,需要这个进程等待,CPU不会跟着等待,通过操作系统改完相应状态数字,然后将这个进程(结构体变量)从运行队列放入磁盘的等待队列,而CPU继续跑其它进程。

进程在等待外设资源的状态,称为阻塞状态。
所谓进程的不同状态,本质是进程在不同的队列中,等待某种资源。
在这里插入图片描述
当磁盘准备好后,操作系统将进程对应状态改为R后,由CPU自动运行之后的代码。

  • 进程的挂起状态

进程的挂起状态是需要经过阻塞状态的。

如果当一个进程进入阻塞,进程放入硬件等待队列,此时进程被加载到内存,但是没有任何用处。
在此前提下,如果内存空间不够用了,操作系统就会在内存中保留进程控制块,将代码和数据放入磁盘中,这样原来的空间就可以提供给其它进程。(这样就完成了一个进程的挂起!)

进程挂起:进程暂时将代码和数据换出到磁盘。

所以阻塞不一定挂起,而挂起就一定阻塞,挂起是阻塞的一种状态。
这里是引用


3.2 具体的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(运行)状态

通过运行一个小程序,再查看它的进程状态。

  1 #include <stdio.h>                                                                                                                              
  2 
  3 int main()                            
  4 {                                     
  5     int i = 0;                        
  6     while(1)                          
  7     {                                 
  8         i = 1+1;                      
  9     }                                 
 10     return 0;                         
 11 }

在这里插入图片描述

这样一个程序不断运行,相应状态也就对应R。
这里的+号代表前台进程,是可以通过ctrl+c终止的,如果不带+就是后台进程,只能通过kill中止进程。

  • Linux下的S(休眠)状态
  1 #include <stdio.h>  
  2 #include <unistd.h>                                                                                                                             
  3                                          
  4 int main()                               
  5 {                                        
  6     int i = 0;                           
  7     while(1)                             
  8     {                                    
  9         printf("%d\n",i++);              
 10         sleep(3);                                                                                                               
 11     }                                                                                                                           
 12     return 0;                                                                                               
 13 }

在这里插入图片描述

有人可能疑问,这个程序明明一直在运行,为什么不是R状态,而是S状态呢?其实这个程序就体现了CPU和外设的速度差距,只要体会到CPU在等外设这点,就很好理解进程进入了S状态。

  • Linux下的D(深度休眠)状态

这个状态不好显示,但是我们可以谈谈它的场景。

D状态防止的场景
  进程A写入磁盘的过程中,磁盘(较慢)读取进程A的数据,进程A进入等待状态,此时内存由于负载太高导致操作系统需要删除一些不用的进程,此时进程A在操作系统看起来就是不用的进程,删除了等待状态的进程A,造成数据损坏。

赋予进程A深度睡眠状态,在该进程下无法被操作系统删除,只能断电或自己醒来才能解决。

  • Linux下的T(暂停)状态

对正在运行的进程运用kill -19 PID 暂停进程

在这里插入图片描述

如果需要再次运行

kill -18 PID 继续进程
在这里插入图片描述
但值得注意的是,这里再继续进程的时候,进程就属于了后台进程。

  • Linux下的t(暂停)状态

这个暂停状态和上面暂停状态不同的是,上面的状态能通过Kill命令18信号进行唤醒,这个不会响应kill命令中的信号。

它还有另一种称号叫,正在被追踪状态,指的是进程暂停,等待跟踪它的进程对它的操作(比如当进程被调试的时候,等待gdb进程对它的操作)。

当process正在gdb调试中
在这里插入图片描述

还有Z、X状态我们放在下面开始。


3.3 僵尸进程

当进程退出并且父进程没有读取到子进程退出的返回代码时就会产生僵死(尸)进程。

  • 为什么要有僵尸进程?

一个进程被创建出来,是为了完成任务的。
操作系统要知道它完成的如何,所有进程在退出时,不能立即释放其资源,需要保存一段时间,让OS或其父进程来读取。

通过一个小程序。

  1 #include <stdio.h>                                    
  2 #include <unistd.h>                                   
  3 #include <stdlib.h>                                   
  4                                                       
  5 int main()                                            
  6 {                                                     
  7     pid_t id = fork();                                
  8     if(id == 0)                                       
  9     {                                                 
 10         printf("我是子进程,pid: %d, ppid: %d\n", getpid(), getppid());  
 11         sleep(5);                                     
 12         exit(1);                                      
 13     }                                                 
 14     else                                              
 15     {                                                 
 16         while(1)                                      
 17         {                                             
 18             printf("我是父进程, pid: %d, ppid: %d\n", getpid(), getppid());                                                                     
 19             sleep(1);                                                                              
 20         }                                                                                          
 21     }                                                                                              
 22                                                                                                    
 23     return 0;                                                                                      
 24 }

代码解释:
利用fork调用,运行两个进程,当子进程结束,让父进程一直运行什么也不做,这时父进程就不能读取其子进程。

运行结果
在这里插入图片描述

再通过一个脚本持续查看进程状态
while :; do ps ajx | head -1 && ps ajx | grep myprocess | grep -v myprocess.c | grep -v grep; sleep 1; done
在这里插入图片描述
子进程正常退出死亡,但是资源没有被释放,处于Z状态。

只要子进程退出,父进程还在运行,但父进程没有读取子进程状态,子进程进入Z状态。
在子进程正常退出,并且资源被释放后,就是X(死亡)状态。

  • 内存泄漏

处于僵尸状态的进程,已经退出但是资源没有被释放完全,如父进程永远不回收,子进程资源永远占用内存就成了内存泄漏。(进程中的代码和数据可能释放,对应的PCB可能会被保留下)


3.4 孤儿进程

下面通过一个程序认识孤儿进程

  1 #include <stdio.h>
  2 #include <unistd.h>                                                                                                                                 
  3 
  4 int main()                            
  5 {                                     
  6     pid_t id = fork();                
  7     if(id == 0)                       
  8     {                                 
  9         while(1)                      
 10         {                             
 11             printf("我是子进程, pid: %d, ppid: %d\n", getpid(), getppid());
 12             sleep(1);                                                      
 13         }                             
 14     }                                 
 15     else                              
 16     {                                 
 17         while(1)                                                           
 18         {                                                                                
 19             printf("我是父进程, pid: %d, ppid: %d\n", getpid(), getppid());
 20             sleep(1);                                                      
 21         }                             
 22     }                                                                      
 23                                       
 24     return 0;                         
 25 }

上述代码利用fork系统调用,让父子进程不断运行。
在这里插入图片描述

当进程运行的时候,我们通过kill -9 27455 杀死父进程。
在这里插入图片描述
在这里插入图片描述

通过杀死父进程,被bash回收,当前的进程被1号进程(init进程)领养,而一旦被领养就成了后台程序,只能被kill杀死。
在这里插入图片描述
父进程先退出,子进程就称之为“孤儿进程”

子进程为什么会被操作系统领养?

很简单,如果不领养,子进程在退出后就成了僵尸进程,没有进程来回收。


本章完~

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

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

相关文章

【cmake】cmake应用:安装和打包

【cmake】cmake应用&#xff1a;安装和打包 在本系列前序的文章中已经介绍了CMake很多内容&#xff0c;在CMake应用&#xff1a;CMakeLists.txt完全指南一文中简略介绍了安装和打包&#xff0c;本文会更加深入地介绍CMake的安装和打包功能。【cmake】cmake应用&#xff1a;安装…

分享500道我在“金九银十”收集的Java架构面试题

前段时间&#xff0c;字节跳动官方就发布消息称在武汉扩招至5000人&#xff0c;放出了2000个岗位名额。可见&#xff0c;互联网大厂岗位需求仍然奇缺。 在已经过去的“金九银十”&#xff0c;我有许多朋友就已经成功的跳槽&#xff0c;有的还在家等候下一步的面试通知。我托朋…

【计算机扫盲】计算机的基础操作你知多少?

计算机的高级操作 控制面板 ​ 控制面板&#xff08;control panel&#xff09;是Windows图形用户界面的一部分&#xff0c;可通过开始菜单访问。它允许用户查看并操作基本的系统设置&#xff0c;比如添加/删除软件&#xff0c;控制用户帐户&#xff0c;更改辅助功能选项。 …

CAS号:60535-02-6,二肽Met-Trp

血管紧张素-1转换酶(ACE)非竞争性抑制剂IC₅₀9.8 μM。 编号: 154290中文名称: 二肽Met-Trp英文名: Met-TrpCAS号: 60535-02-6单字母: H2N-MW-OH三字母: H2N-Met-Trp-COOH氨基酸个数: 2分子式: C16H21N3O3S1平均分子量: 335.42精确分子量: 335.13等电点(PI): 6.11pH7.0时的净电…

服装连锁店管理系统 服装连锁店如何高效管理 服装连锁店管理怎么走捷径

服装连锁店管理繁杂&#xff0c;难以把控&#xff0c;好在有“捷径”可走。 开服装连锁店的老板&#xff0c;来看看这是不是你的“头痛”日常&#xff1a; 新品上市&#xff0c;加盟店全上了&#xff0c;但无法迅速判断出畅销品和滞销品&#xff0c;搜集数据速度慢&#xff0c;…

Coursera自动驾驶1.4——车辆建模

文章目录一、运动学建模&#xff08;二维&#xff09;1.坐标系转换2.两轮机器人运动学建模3.两轮自行车运动学建模&#xff08;1&#xff09;后轴参考点&#xff08;2&#xff09;前轴参考点&#xff08;3&#xff09;重心参考点二、基本动力学模型&#xff08;2D&#xff09;1…

中台和微服务有什么区别?

中台不就是微服务吗&#xff1f;这种说法实际上混淆了中台与微服务的定义&#xff0c;要说清楚这个问题&#xff0c;就要先了解&#xff0c;什么是中台&#xff1f;什么是微服务&#xff1f;中台和微服务之间有什么样的关系&#xff1f; 什么是中台 来自阿里官方的定义&#x…

【强化学习】TensorFlow2实现DQN(处理CartPole问题)

文章目录1. 情景介绍2. DQN&#xff08;Deep Q Network&#xff09;核心思路&#xff1a;3. DQN算法流程4. 代码实现以及注释5. 实验结果文章阅读预备知识&#xff1a;Q Learning算法的基本流程、TensorFlow2多层感知机的实现。1. 情景介绍 CartPole问题&#xff1a;黑色小车上…

【并发编程五】c++进程通信——信号量(semaphore)

【并发编程五】c进程通信——信号量&#xff08;semaphore&#xff09;一、概述二、信号量三、原理四、过程1、进程A过程2、进程B过程五、demo1、进程A2、进程B六、输出七、windows api介绍1. 创建信号量 CreateSemaphore()2. 打开信号量 OpenSemaphore()3. 等待 WaitForSingle…

一种基于IO口的模拟串口(LOG)实现方法

一、使用背景 当MCU的串口不够用时&#xff0c;可以通过IO模拟的方式将任意一个具有输出功能的管脚配置为串口输出&#xff0c;从而方便开发和调试。 二、实现原理 通过IO口模拟串口发送波形&#xff0c;配置对应的波特率等信息&#xff0c;然后映射printf函数&#xff0c;从…

基于粒子群优化算法的冷热电联供型综合能源系统运行优化(Matlab代码实现)

&#x1f468;‍&#x1f393;个人主页&#xff1a;研学社的博客 &#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜…

redis 支持的数据类型

Redis 数据库支持五种数据类型。 字符串&#xff08;string&#xff09; 哈希&#xff08;hash&#xff09; 列表&#xff08;list&#xff09; 集合&#xff08;set&#xff09; 有序集合&#xff08;sorted set&#xff09; 位图 ( Bitmaps ) 基数统计 ( HyperLogLogs ) 字…

Vue3.2 + Element-Plus 二次封装 el-table(Pro版)

前言 &#x1f4d6; ProTable 组件目前已是 2.0版本&#x1f308;&#xff0c;在 1.0版本 中大家提出的问题与功能优化&#xff0c;目前已经得到优化和解决。 &#x1f600; 欢迎大家在使用过程中发现任何问题或更好的想法&#xff0c;都可以在下方评论区留言&#xff0c;或者我…

【计算机网络】局域网体系结构、以太网Ethernet详解

注&#xff1a;最后有面试挑战&#xff0c;看看自己掌握了吗 文章目录局域网LAN决定局域网的要素网络拓扑传输介质局域网的分类以太网令牌环网FDDI网----Fiber Distributed Data InterfaceATM网---Asynchronous Transfer Mode无线局域网WLAN----Wireless Local Area NetworkMAC…

Red Hat Enterprise Linux (RHEL) 9 更新了哪些新特性?

文章目录1. 前言2. 软件3. 支持的硬件架构4. GNOME更新到40版5. 安全和身份6. 构建容器的通用基础镜像7. 改进了用于管理 RHEL 9 的 Cockpit Web 控制台1. 前言 体验一下最新的rhel 9.0 是什么感觉。它会飞吗&#xff1f; Red Hat Enterprise Linux (RHEL) 9现已普遍可用 (GA…

吃柿子的禁忌靠谱吗?

图片来源&#xff1a;pixabay 秋冬是柿子上市的季节&#xff0c;虽然柿子并不是苹果、香蕉这样的大宗水果&#xff0c;但是秋天不吃个柿子&#xff0c;冬天不吃个柿饼&#xff0c;总觉得少了点什么。 关于吃柿子有很多禁忌&#xff0c;比如说柿子不能与螃蟹同时吃&#xff0c;柿…

​怎么保留硬盘数据合并分区 ,如何才能合并且不丢失数据

硬盘分区合并是比较常见的操作&#xff0c;​怎么保留硬盘数据合并分区&#xff0c;还是具有一定的难度。因为在Windows操作系统中&#xff0c;用户可以通过磁盘管理来实现硬盘分区合并&#xff0c;但是要删除该磁盘分区右侧的相邻分区&#xff0c;但是对于部分不懂计算机的用户…

Tailscale的子网路由和出口节点

2 年前&#xff0c;老苏写了 『 外网访问群晖的新方案Tailscale 』&#xff0c;第一次隆重的给大家推荐了 Tailscale&#xff0c;但当时还有很多功能并不具备&#xff0c;比如今天要介绍的 Subnet Router 和 Exit Node 【特别说明】&#xff1a;老苏使用的是DSM6 &#xff0c;所…

RabbitMQ初步到精通-第一章-消息中间件介绍

第一章 消息中间件介绍 1.MQ概述 MQ全称是Message Queue&#xff0c;消息的队列&#xff0c;因为是队列&#xff0c;所以遵循FIFO 先进先出的原则&#xff0c;它是一种跨进程的通信机制&#xff0c;用于上下游传递消息。 在互联网架构中&#xff0c;MQ是一种非常常见的上下游“…

论文阅读笔记 | 三维目标检测——VeloFCN算法

如有错误&#xff0c;恳请指出。 文章目录paper&#xff1a;《Vehicle Detection from 3D Lidar Using Fully Convolutional Network》 对于64线激光雷达全范围扫描出来的点云进行特征图的构建。对于具体的点&#xff08;xyz坐标&#xff09;&#xff0c;其在水平方向上可以通…