【Linux】进程概念(2)(进程 操作系统管理进程 PCB(struct task_struct) 查看进程 进程的常见调用 系统调用 man getpid/getppid man fork)

本文主要是介绍【Linux】进程概念(2)(进程 操作系统管理进程 PCB(struct task_struct) 查看进程 进程的常见调用 系统调用 man getpid/getppid man fork),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

  • 进程
    • 概念
  • 操作系统管理进程
    • PCB(struct task_struct)结构体
  • 查看进程
    • 另一种查看进程的方式:
  • 进程的常见调用
    • 系统调用
      • man getpid
      • man getppid
      • man fork


进程

概念

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

一个运行起来(加载到内存)的程序 — 进程
在内存中的程序 — 进程
进程和程序相比,进程具有动态属性

操作系统管理进程

操作系统如何管理进程?

先描述再组织,要管理这些进程,操作系统首先将这些进程描述,所以就引出了一个叫做PCB的概念,

PCB(struct task_struct)结构体

在这里插入图片描述
操作系统为了管理进程,给PCB里面写上包含了进程的所有属性,理所当然,这里的属性有几百个,我们通过每个进程对应的ID来进行管理。进程控制块里面保存的是进程被创建时的所有属性,这些属性不在我们曾经的可执行程序里面,可执行程序里面只有我们的代码数据和逻辑。

struct task_struct
{//进程的所有属性//该进程对应的代码和属性地址struct task_struct *next;}

struct tack_struct *next包含了大堆的指针信息,对我们来讲,描述每一个进程都是一个task_struct

task_struct内容分类:

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

每一个程序加载进内存,每一个进程对应的代码和数据在加载的时候,操作系统要进行操作,然后就初始化完了一个task_struct结构体,

在这里插入图片描述

其中每一个进程都要做这个工作,所以在系统里面,除了加载进程到内存里,操作系统给每一个可执行程序匹配一个进程控制块,说白了就是task_struct所对应的结构体对象或者变,然后它们每一个都指向自己的代码,到这里就完成了先描述,然后再组织,操作系统把所有的进程的PCB,结构体对象链接起来,拿着process_header这个头,CPU要调度某个进程,操作系统就遍历所有进程的PCB,然后找到优先级最高的进程,比如说process_header指向的那个,然后把代码交给CPU,CPU就可以执行对应进程的代码了,若以后有一个进程想退出了,我们只需要确定PCB属性里面有没有一个进程的状态是死亡的,死亡的话操作系统遍历链表,把状态是死亡的节点找到,然后把对应的代码和数据释放掉,然后把PCB释放掉,此时这个进程就会释放了。
在这里插入图片描述

最后我们有了先描述再组织这样的理念,我们得出一个结论:**所谓的对进程管理,变成了对进程对应的PCB进行相关的管理。对进程管理本质不是对进程的可执行程序管理,而是对应的PCB结构做管理。
对进程管理——转化成立对链表的增删查

struct task_struct是一个内核结构体,是操作系统给我们提供的用来描述进程的结构体,当加载进程的时候会创建对应的内核对象task_struct 对象(内核变量),并且将结构和我们的代码和数据关联起来从而完成先描述再组织的工作。

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

查看进程

-rw-rw-r-- 1 test_106 test_106   76 Nov 11 17:09 Makefile
-rwxrwxr-x 1 test_106 test_106 8408 Nov 11 17:16 myproc
-rw-rw-r-- 1 test_106 test_106  135 Nov 11 17:16 myproc.c

进程在运行,本质是进程读取代码,依次做执行,进程在被调度运行的时候,进程就具有动态属性。

[test_106@VM-4-13-centos 20221111]$ man getpid
[test_106@VM-4-13-centos 20221111]$ ps ajx | head -1 && ps axj | grep 'myproc'

另一种查看进程的方式:

一个进程每一次被启动,就意味着每一次被重新加载到内存,每一次被重新加载到内存就意味这操作系统每一次都要给这个进程创建task_struct,重新分配PID,所以PID不断变化。
在Linux当中有一个目录结构:proc,它是一个内存级的目录
[test_106@VM-4-13-centos 20221111]$ ls /proc/
在这里插入图片描述

我们可以看到有一些目录是以数字开头,其实那些数字就是对应进程的PID
在这里插入图片描述
在Linux下,一个进程可以被当做文件来看待,最后我们可以通过proc这个目录来查到对应的属性信息。
[test_106@VM-4-13-centos 20221111]$ ls /proc/5660 -d
在这里插入图片描述
进程一退出,目录就自动删除了。

一个进程被加载到内存,这个进程已经跑起来了,现在把它在磁盘中的二进制程序删了,请问进程还能不能正常运行?
结果是还能。
在这里插入图片描述

进程的常见调用

系统调用

man getpid

在这里插入图片描述

返回值pid_t是系统给我们封装的类型,其实就是整数。提供的接口,谁调用就返回调它进程的PID。

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

在这里插入图片描述
在这里插入图片描述
杀掉进程:kell -9 1193

man getppid

第一个p表示父,main getppid表示获取父进程ID,

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

在这里插入图片描述
关掉进程,再次打开,我们发现子进程一直在变,父进程pid不变化,我们查看:
[test_106@VM-4-13-centos 20221111]$ ps ajx | grep 7651

在这里插入图片描述

我们发现7651进程的PID叫做bash
命令行上启动的进程,一般它的父进程没有特殊情况的话,都是bash!

man fork

  • 运行 man fork 认识fork
  • fork有两个返回值
  • 父子进程代码共享,数据各自开辟空间,私有一份(采用写时拷贝)
    在这里插入图片描述
    创建子进程:fork - create a child process fork 是一个函数.
    函数执行前:只有一个父进程,函数执行后:父进程+子进程
  1 #include<stdio.h>2 #include<unistd.h>3 #include<sys/types.h>4 int main()5 {6   fork();7   printf("我是一个进程,pid:%d,ppid:%d\n",getpid(),gitppid());8   sleep(2);                                                                                                                     14   return 0;15 }  

在这里插入图片描述

  1 #include<stdio.h>2 #include<unistd.h>3 #include<sys/types.h>4 int main()5 {6   pid_t id = fork();7   printf("我是一个进程,pid: %d ,ppid:%d,id: %d\n",getpid(),getppid(),id);                                                     8   sleep(2);                                                                                                                     14   return 0;                                                          15 } 

在这里插入图片描述
同一个变量id,在后续不会被修改的情况下,竟然有不同的内容!

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

在这里插入图片描述
创建出来了多进程,在C语言中if和else if不能同时条件成立,以前写的代码,两个死循环不能同时跑,证明fork之后会有父进程+子进程两个进程在执行后续代码,fork后续的代码,被父子进程共享。通过返回值不同,让父子进程执行后续共享的代码的一部分!

这篇关于【Linux】进程概念(2)(进程 操作系统管理进程 PCB(struct task_struct) 查看进程 进程的常见调用 系统调用 man getpid/getppid man fork)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/625750

相关文章

防止Linux rm命令误操作的多场景防护方案与实践

《防止Linuxrm命令误操作的多场景防护方案与实践》在Linux系统中,rm命令是删除文件和目录的高效工具,但一旦误操作,如执行rm-rf/或rm-rf/*,极易导致系统数据灾难,本文针对不同场景... 目录引言理解 rm 命令及误操作风险rm 命令基础常见误操作案例防护方案使用 rm编程 别名及安全删除

Linux下MySQL数据库定时备份脚本与Crontab配置教学

《Linux下MySQL数据库定时备份脚本与Crontab配置教学》在生产环境中,数据库是核心资产之一,定期备份数据库可以有效防止意外数据丢失,本文将分享一份MySQL定时备份脚本,并讲解如何通过cr... 目录备份脚本详解脚本功能说明授权与可执行权限使用 Crontab 定时执行编辑 Crontab添加定

SpringBoot 多环境开发实战(从配置、管理与控制)

《SpringBoot多环境开发实战(从配置、管理与控制)》本文详解SpringBoot多环境配置,涵盖单文件YAML、多文件模式、MavenProfile分组及激活策略,通过优先级控制灵活切换环境... 目录一、多环境开发基础(单文件 YAML 版)(一)配置原理与优势(二)实操示例二、多环境开发多文件版

使用docker搭建嵌入式Linux开发环境

《使用docker搭建嵌入式Linux开发环境》本文主要介绍了使用docker搭建嵌入式Linux开发环境,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面... 目录1、前言2、安装docker3、编写容器管理脚本4、创建容器1、前言在日常开发全志、rk等不同

深度解析Java @Serial 注解及常见错误案例

《深度解析Java@Serial注解及常见错误案例》Java14引入@Serial注解,用于编译时校验序列化成员,替代传统方式解决运行时错误,适用于Serializable类的方法/字段,需注意签... 目录Java @Serial 注解深度解析1. 注解本质2. 核心作用(1) 主要用途(2) 适用位置3

JWT + 拦截器实现无状态登录系统

《JWT+拦截器实现无状态登录系统》JWT(JSONWebToken)提供了一种无状态的解决方案:用户登录后,服务器返回一个Token,后续请求携带该Token即可完成身份验证,无需服务器存储会话... 目录✅ 引言 一、JWT 是什么? 二、技术选型 三、项目结构 四、核心代码实现4.1 添加依赖(pom

Redis实现高效内存管理的示例代码

《Redis实现高效内存管理的示例代码》Redis内存管理是其核心功能之一,为了高效地利用内存,Redis采用了多种技术和策略,如优化的数据结构、内存分配策略、内存回收、数据压缩等,下面就来详细的介绍... 目录1. 内存分配策略jemalloc 的使用2. 数据压缩和编码ziplist示例代码3. 优化的

redis-sentinel基础概念及部署流程

《redis-sentinel基础概念及部署流程》RedisSentinel是Redis的高可用解决方案,通过监控主从节点、自动故障转移、通知机制及配置提供,实现集群故障恢复与服务持续可用,核心组件包... 目录一. 引言二. 核心功能三. 核心组件四. 故障转移流程五. 服务部署六. sentinel部署

SpringBoot集成XXL-JOB实现任务管理全流程

《SpringBoot集成XXL-JOB实现任务管理全流程》XXL-JOB是一款轻量级分布式任务调度平台,功能丰富、界面简洁、易于扩展,本文介绍如何通过SpringBoot项目,使用RestTempl... 目录一、前言二、项目结构简述三、Maven 依赖四、Controller 代码详解五、Service

基于Python实现自动化邮件发送系统的完整指南

《基于Python实现自动化邮件发送系统的完整指南》在现代软件开发和自动化流程中,邮件通知是一个常见且实用的功能,无论是用于发送报告、告警信息还是用户提醒,通过Python实现自动化的邮件发送功能都能... 目录一、前言:二、项目概述三、配置文件 `.env` 解析四、代码结构解析1. 导入模块2. 加载环