【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

相关文章

Windows系统宽带限制如何解除?

《Windows系统宽带限制如何解除?》有不少用户反映电脑网速慢得情况,可能是宽带速度被限制的原因,只需解除限制即可,具体该如何操作呢?本文就跟大家一起来看看Windows系统解除网络限制的操作方法吧... 有不少用户反映电脑网速慢得情况,可能是宽带速度被限制的原因,只需解除限制即可,具体该如何操作呢?本文

windows和Linux使用命令行计算文件的MD5值

《windows和Linux使用命令行计算文件的MD5值》在Windows和Linux系统中,您可以使用命令行(终端或命令提示符)来计算文件的MD5值,文章介绍了在Windows和Linux/macO... 目录在Windows上:在linux或MACOS上:总结在Windows上:可以使用certuti

CentOS和Ubuntu系统使用shell脚本创建用户和设置密码

《CentOS和Ubuntu系统使用shell脚本创建用户和设置密码》在Linux系统中,你可以使用useradd命令来创建新用户,使用echo和chpasswd命令来设置密码,本文写了一个shell... 在linux系统中,你可以使用useradd命令来创建新用户,使用echo和chpasswd命令来设

电脑找不到mfc90u.dll文件怎么办? 系统报错mfc90u.dll丢失修复的5种方案

《电脑找不到mfc90u.dll文件怎么办?系统报错mfc90u.dll丢失修复的5种方案》在我们日常使用电脑的过程中,可能会遇到一些软件或系统错误,其中之一就是mfc90u.dll丢失,那么,mf... 在大部分情况下出现我们运行或安装软件,游戏出现提示丢失某些DLL文件或OCX文件的原因可能是原始安装包

电脑显示mfc100u.dll丢失怎么办?系统报错mfc90u.dll丢失5种修复方案

《电脑显示mfc100u.dll丢失怎么办?系统报错mfc90u.dll丢失5种修复方案》最近有不少兄弟反映,电脑突然弹出“mfc100u.dll已加载,但找不到入口点”的错误提示,导致一些程序无法正... 在计算机使用过程中,我们经常会遇到一些错误提示,其中最常见的就是“找不到指定的模块”或“缺少某个DL

gradle第三方Jar包依赖统一管理方式

《gradle第三方Jar包依赖统一管理方式》:本文主要介绍gradle第三方Jar包依赖统一管理方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录背景实现1.顶层模块build.gradle添加依赖管理插件2.顶层模块build.gradle添加所有管理依赖包

基于Python打造一个智能单词管理神器

《基于Python打造一个智能单词管理神器》这篇文章主要为大家详细介绍了如何使用Python打造一个智能单词管理神器,从查询到导出的一站式解决,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1. 项目概述:为什么需要这个工具2. 环境搭建与快速入门2.1 环境要求2.2 首次运行配置3. 核心功能使用指

C#如何调用C++库

《C#如何调用C++库》:本文主要介绍C#如何调用C++库方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录方法一:使用P/Invoke1. 导出C++函数2. 定义P/Invoke签名3. 调用C++函数方法二:使用C++/CLI作为桥接1. 创建C++/CL

Linux之systemV共享内存方式

《Linux之systemV共享内存方式》:本文主要介绍Linux之systemV共享内存方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、工作原理二、系统调用接口1、申请共享内存(一)key的获取(二)共享内存的申请2、将共享内存段连接到进程地址空间3、将

Java Spring 中 @PostConstruct 注解使用原理及常见场景

《JavaSpring中@PostConstruct注解使用原理及常见场景》在JavaSpring中,@PostConstruct注解是一个非常实用的功能,它允许开发者在Spring容器完全初... 目录一、@PostConstruct 注解概述二、@PostConstruct 注解的基本使用2.1 基本代