【Linux】进程概念(万字详解)—,2024年最新腾讯T2亲自教你

先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7

深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新大数据全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上大数据知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以添加V获取:vip204888 (备注大数据)
img

正文

🌈是什么what?

操作系统,是一款专门针对软硬件进行管理软件

🌈为什么why?

在整个计算机软硬件架构中,操作系统的定位是:一款纯正的“搞管理”的软件

  • 对上:给用户提供稳定、高效、安全的运行环境 —— 目的
  • 对下:管理好软硬件资源 —— 方式

🌈怎么样管理how?

🌊以学校中的管理类比,操作系统中——在学校里大概有这三种角色:

  1. 管理者和被管理者并不会直接打交道(就好像你在学校见过校长吗❓)
    学生 (被管理者) —— 软硬件
    辅导员 (执行者) —— 驱动
    校长 (管理者) —— 操作系统
  2. 如何管理我们?
    对我们做出各种决策,依据就是你的核心数据
  3. 校长是如何做执行的?你的数据如何被校长拿到?
    通过辅导员

🚩站在校长的角度———

  • 用结构体来描述一个学生的数据
  • 来用特定的数据结构来组织,于是对学生的管理工作,变成了对数据结构的增删查改———对多个学生进行管理!

⚡管理的理念—— 先描述,再组织

  • 先描述:被管理的对象
  • 再组织:将被管理的对象用特定的数据结构组织起来

🌏对应到操作系统——

在这里插入图片描述
⚡系统调用和库函数概念 ❗

  1. 在开发角度,操作系统对外会表现为一个整体,它不相信任何用户,但是会暴露自己的部分接口供上层开发者使用,这部分由操作系统提供的接口,叫做系统调用。
  2. 系统调用在使用上,功能比较基础,对用户的要求相对也比较高,所以,有心的开发者就对部分系统调用进行适度封装,从而形成库,有了库,就很有利于更上层用户或者开发者进行二次开发。

类似于银行取钱时,一般都会雇佣服务人员 (库),王大爷不会取钱,就叫指导人员来指导 (调用库)。其实对于库函数的使用要么使用了 SystemCall,如 printf 函数;要么没使用 SystemCall,如 sqrt 函数。

操作系统是怎么管理进行进程管理的呢?很简单,先把进程描述起来,再把进程组织起来!

三、进程 (process)

🌊基本概念

  • 课本概念:程序的一个执行实例,正在执行的程序等
  • 内核观点:担当分配系统资源(CPU时间,内存)的实体
    在这里插入图片描述

当我们启动一个软件的时候,本质上就是启动了一个进程
在linux中运行一条命令./xxx运行的时候,其实就是在系统层面创建了一个进程

Linux是可以同时加载多个程序的,Linux是可能同时存在大量的进程在系统的OS、内存

🌊描述进程-PCB

为什么要有PCB?因为我们要先描述进程,后管理

在任何进程形成的时候,操作系统要为进程创建PCB(process control block),进程控制块 —— 就是描述进程的结构体

我们知道:文件 = 内容 + 属性
把mytest.exe加载到内存里,本质上只是把内容加载到内存里,可是我们要管理进程,这里就需要大量的PCB结构来描述这里的进程,其中PCB包含了进程所有的属性:(包括了代码在哪、数据在哪、谁启动、什么时间启动的)

在这里插入图片描述

对进程的管理,变成了对进程PCB结构体链表的增删查改❗
在这里插入图片描述

🔥🔥什么是进程?

进程 = 对应的代码和数据 + 进程对应的PCB结构体

struct PCB
{
	//属性数据,进程全部的属性数据 
}

Linux 操作系统下的 PCBtask_struct,相当于是媒婆和王婆之间的关系。它会被装载到 RAM(内存) 里并且包含着进程的信息。

struct task\_struct
{
	//进程全部属性数据 
}

🌌 task_struct中有什么属性字段?

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

🌊组织进程

可以在内核源代码里找到它。所有运行在系统里的进程都以task_struct链表的形式存在内核里。

四、查看进程

我写了一段程序myproc.c就是隔1s打印,./运行,同时复制SSH渠道再打开一个窗口,便于监视进程。

💦查看进程

ps axj | grep "myproc" 

🌈关闭进程 ——

[Ctrl + C]
kill -9 [pid] 向目标进程发送9号信号 -- 同时也证明pid能标识系统上的唯一进程

在这里插入图片描述

其中下面的是grep进程,我们不用管

在这里插入图片描述

🌈以文件形式查看进程 ——/proc是Linux系统下查看进程的目录

ls /proc
top  //不常用 相当于任务管理器

进程启动后,会在/proc下形成目录,以自身PID的编号作为目录文件名 ——

在这里插入图片描述

🌈查看该进程的属性数据

在这里插入图片描述

每个进程都会有一个属性,来保存自己所在的工作路径

ls / proc 目录中,当我们停止掉某个进程,此进程目录就会消失所以proc目录是动态

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

我们可以使用 man 2 getpid/getppid 命令来查看人生中第一个系统调用接口

💛 查看进程PID

在这里插入图片描述

执行以下代码———

 #include<stdio.h>
 #include<unistd.h>
   
 int main()
 {
     while(1)
     {
       pid\_t id = getpid();//获取的是自己进程的PID
      printf("hello world! pid: %d\n",id);                                               
      sleep(1);
     }
  }

在这里插入图片描述

父进程

执行以下代码———

 #include<stdio.h>
 #include<unistd.h>
  
 int main()
 {
    while(1)
    {
      pid\_t pid = getppid();//父进程
      pid\_t id = getpid();//获取的是自己进程的PID
      printf("hello world! pid: %d, ppid: %d\n",id,pid);                                            
      sleep(1);
    }
 }

在这里插入图片描述
这里我们发现父进程居然是bash,我们回想一下shell外壳 ❗❗可以看看这篇博客🚩shell外壳详解🚩
我们可以假设,这里的bash是王婆,为了完成任务,但又不想砸了自己的招牌,所以招了个实习生(可以理解成子进程

我们在操作命令行的时候,父进程永远是bash外壳,其原理:shell外壳通过创建子进程的方式,以bash的子进程去执行

每次我们登录成功的时候,系统就会指派一个王婆跟着你,当你输入命令行的时候,王婆会说她帮你创建子进程去执行。卖个关子🚩王婆bash的父进程是谁??

六、通过系统调用创建进程-fork初识

💛 创建子进程

在这里插入图片描述

#include<stdio.h>
#include<unistd.h>
int main()
{
   printf("I am parent process!\n");
   fork();
   
   printf("you can see me ?\n");
   sleep(1);
   return 0;
 }

在这里插入图片描述调用了fork之后,我们发现打印了两次,其实就是又两个进程在实行来执行代码,💡下面我来深入探究

1️⃣如何理解fork创建子进程

✨fork本质是创建进程,系统中多了一个进程,就多了一份与进程相关的内核数据结构PCB + 进程的代码和数据 。 我们fork只是创建了子进程,但是子进程对应的代码和数据呢?

  1. 默认情况下,子进程会继承父进程的代码和数据
    💖代码:父子进程代码共享,但是父子进程对应的id值不同,所以会执行不同的代码
    💖数据:默认情况下,数据也是“共享的”,不过修改时会发生写时拷贝来维护数据的独立性
  2. 子进程内核的数据结构task_struct,也会以父进程的为模板初始化自身

注:if 和 else if 有没有可能是同时执行的呢?

  • 没有!因为id在父进程里面是子进程的pid,在子进程里面是0,所以一般else运行父进程

在这里插入图片描述

2️⃣fork有两个返回值

  1. 如何理解一个函数有两个返回值

1️⃣因为在fork内部,return时子进程已被创建,甚至可以被调度了,父子进程各自会执行return语句。
2️⃣返回两次并不意味着会保存两次(买个关子后面讲👍)
2. 我们创建的子进程和父进程是做相同的事情吗?岂不是没有意义
答:是通过if-else分流,让父子进程各自执行不同的代码段,而这就是通过fork的返回值来完成的。
创建失败<0
创建成功:给父进程返回子进程的PID;给子进程返回0,表示成功创建
3. 为什么给子进程返回0,给父进程返回子进程的pid?
💡首先我们知道:父进程:子进程 = 1:n
💡第二:因为父进程可能会创建多个子进程,这为了保证父进程能拿到想拿到的子进程(你爸给你起名字),而子进程返回 0 的原因是父进程对于子进程是唯一的(好比你不可能给你爸起名字)
在这里插入图片描述
4. 父子进程被创建出来,哪一个进程先运行呢?
答:不一定!!这个是由操作系统的调度器决定

⚡多进程代码,让父子执行不同的事情:if else 分流

 #include<stdio.h>
 #include<unistd.h>
 int main()
 {
     pid\_t id = fork();
     if(id < 0)
     {
       perror("fork");
       return 1;
     }
     else if(id == 0)                                                                                                             
     {
        //子进程
        while(1)
        {
          printf("I am child, pid :%d, ppid: %d\n", getpid(),getppid());
          sleep(1);
        }
     }
     else
     {
        //父进程
        while(1)
        {
          printf("I am father, pid :%d, ppid: %d\n", getpid(),getppid());
          sleep(1);
        }
      }
  return 0;
  }

七、进程状态

进程的状态信息也是在task_struct(PCB)中。进程状态的意义在于,方便OS快速判断进程,并完成特定的功能,比如调度。本质上是一种分类。

💦进程状态

下面的状态在kernel源代码里定义:

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

一个完整的进程状态的变迁如下图————
在这里插入图片描述

⭐️ R 运行状态(running): 并不意味着进程一定在运行中❓ 进程可能在运行队列中等或者正在被执行,就叫做 运行态,随时可以被CPU调度

在这里插入图片描述

⭐️ S 浅度睡眠状态(sleeping) ,也叫做可中断睡眠(interruptible sleep)

  • 等待非CPU资源就绪。这种休眠是可被换醒的,我们可以 Ctrl + C 退出循环,而此时的进程就没了,也就是说它虽然是一种休眠状态,但是它随时可以接收外部的信号,处理外部的请求。

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

  • ⭐️ 挂起状态(也属于S 状态)

内存不足的时候,OS提供适当的置换进程的代码和数据到磁盘中,PCB不换(好比你学籍还在,人把你赶走了)进程的状态就叫做挂起 在这里插入图片描述
📌你现在正在等待某种资源的时候,正巧内存不足了,内存不够是你正在阻塞状态,所以把你的代码数据置换到磁盘里,所以叫做“挂起阻塞

⭐️ D 深度睡眠状态(Disk sleep),也叫不可中断睡眠状态(uninterruptible sleep)
进程处于D状态,不可被杀掉,耶稣来了都没用,只能等这个进程自动醒来,kill -9 都杀不掉它,也得等它醒来 (关机除外,有可能关机都要被磁盘写入卡住,只能拔电源)
在这里插入图片描述
dd命令能够演示D状态进程(想知道的同学可以自行百度)

⭐️ T暂停状态(stopped)
可以通过发送 SIGSTOP(kill -19) 信号给进程来停止(T)进程。这个被暂停的进程可以通过发送 SIGCONT 信号让进程继续运行。

⭐️ X死亡状态(dead)
随时准备被OS回收。此状态只是一个返回状态,无法在任务列表中看到这个状态。因为回收进程是一瞬间发生的事情,我们很难直接捕捉到。

⭐️ Z僵尸状态(Zombie)
💦是什么:一个进程已经退出,但还不允许被OS释放,处于一个被检测的状态(好比出事了,警察要拉警戒线去调查原因),一般是父进程或者OS,想要得知该进程的结果,如何检测呢?这个我们后文再细说

💦为什么? 维持该状态是为了让父进程和OS来回收,从Z状态变成X

在这里插入图片描述

演示R/S/T状态:同样的复制SSH渠道,监视

  1. 运行状态 R ——— 死循环
#include<stdio.h> 
int main()      
{      
  while(1);    
  return 0;    
}  

在这里插入图片描述

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip204888 (备注大数据)
img

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

85d47c7378e76.png)

演示R/S/T状态:同样的复制SSH渠道,监视

  1. 运行状态 R ——— 死循环
#include<stdio.h> 
int main()      
{      
  while(1);    
  return 0;    
}  

在这里插入图片描述

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip204888 (备注大数据)
[外链图片转存中…(img-415A6LFf-1713346766026)]

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 29
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值