进程概念、PCB及进程查看

文章目录

  • 一.进程的概念
    • 进程控制块(PCB)
  • 二.进程查看
    • 通过指令查看进程
    • 通过proc目录查看
    • 进程的`cwd`和`exe`
    • 获取进程pid和ppid
    • 通过fork()创建子进程

一.进程的概念

进程是一个运行起来的程序,而程序是存放在磁盘的,cpu要想执行程序的指令,需要先将程序加载到内存中。

课本概念:进程是被加载到内存运行的程序
内核观点:担当分配系统资源(CPU时间,内存)的实体。

操作系统中有着大量的进程,操作系统作为管理者,管理的其实是大量进程相关的数据,那么如何管理这些数据呢?

先描述,再组织

当二进制代码直接加载到内存时,操作系统为了更好地管理加载的程序,创建了描述该进程的数据结构。这样,操作系统只用看这个数据结构,不用管各种复杂多样的二进制代码,并且将它们组织起来进行管理

进程控制块(PCB)

这个数据结构叫PCB(process control block),进程信息被放在其中,可以理解为进程属性的集合,在linux的PCB是task_struct

struct task_struct {volatile long state; /* -1 unrunnable, 0 runnable, >0 stopped */struct thread_info *thread_info;atomic_t usage;unsigned long flags; /* per process flags, defined below */unsigned long ptrace;int lock_depth;  /* Lock depth */int prio, static_prio;struct list_head run_list;prio_array_t *array;//.....
}

当有一个程序被加载到内存时,操作系统会为该进程在内存中创建一个task_struct类型的对象,并将该进程放入双链表等其他结构中。这样,操作系统对进程的管理就变为操作系统对PCB的管理,再变为操作系统对双链表等结构的增删查改等操作

由此可以总结:进程 = 内核数据结构(PCB等)+ 可执行程序(代码+数据)

二.进程查看

通过指令查看进程

为了让进程能够一直运行方便观察,写一个死循环程序,让其每隔1秒钟打印一句话。

#include <stdio.h>
#include <unistd.h>int main()
{while(1){printf("It's a process.\n");sleep(1);}return 0;
}

随后运行它,此时该程序变成了一个进程:
在这里插入图片描述

接着就可以用ps指令查看进程信息,同时配合grep进行抓取

ps ajx | grep myprocess

得到以下结果:
在这里插入图片描述

可以看到系统中关于myprocess的进程一共有两个,第一行是我们写的运行的程序,第二行是grep命令进行抓取的进程。展示了各种信息:PPID、PID、PGID等等,这些就是PCB的一部分。
注意:task_struct是内核数据结构,查看进程信息读取该数据,必须要通过系统调用。

通过proc目录查看

proc是一个目录,里面存放当前系统实时的 进程信息
ls /proc
在这里插入图片描述

这里的数字就是进程的PID,由于此时已经将myprocess进程停止,此目录并没有找到名为167647的目录。
但是,仔细看,却有165058,这是刚才myprocess的父进程ID即PPID,通过指令可以知道,该进程其实就是bash
在这里插入图片描述

再次运行myprocess,并且通过指令得到其PID,进入该文件夹,可以发现进程的数据显式存在文件中。

在这里插入图片描述

进程的cwdexe

查看该目录详细信息,有两个文件很瞩目
在这里插入图片描述

cwd: Current Work Directory 指出该进程当前工作路径
exe: 指出该进程可执行程序的磁盘文件

修改程序,添加一个fopen函数

#include <stdio.h>
#include <unistd.h>int main() 
{FILE* fp = fopen("1.txt", "w");  // 若不存在就创建while (1) {printf("It's a process.\n");sleep(1);}
}

在这里插入图片描述

这恰好就是cwd链接的目录,说明fopen使用了查看cwd的系统调用。


再看exe,此时进程运行中,直接删除其链接在磁盘中的文件,发现进程没有终止,停止进程再运行显然就会失败了。
在这里插入图片描述

运行程序,本质就是将其从磁盘拷贝至内存中,进程与其磁盘上对应程序没有直接关系。

获取进程pid和ppid

可以直接通过系统调用getpid()getppid()得到当前进程的pid和ppid(父进程的pid),返回值为pid_t类型,底层就是整数。

运行以下代码

#include <stdio.h>
#include <unistd.h>int main()
{while (1){printf("It's a process.\t");printf("pid:%d, ppid:%d\n",getpid(), getppid());sleep(1);}return 0;
}

可以看到打印出当前进程的pidppid
在这里插入图片描述

通过ps axj | head -1; ps axj | grep 184670进行验证,当前进程是./myprocess且其父进程是bash

在这里插入图片描述

通过fork()创建子进程

通过man指令查看fork()函数细节
在这里插入图片描述

fork()函数可以创建子进程,创建成功后父子进程代码共享。
若成功创建,子进程的pid返回给父进程,0返回给子进程;
若失败,-1返回给父进程,没有子进程。

代码共享可以通过以下代码得到验证

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>int main() 
{printf("before\n");fork();printf("Hello, pid:%d\n", getpid());
}

fork()之前的代码只执行了一次,之后的代码执行了两次,这两次分别是两个进程执行的。
在这里插入图片描述


创建父子进程是为了做不同的事情,一般是通过if/else来进行分流达到的,这恰恰用到了fork()有两个返回值的特点,下面的代码若是初见一定会迷惑。

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>int main() 
{pid_t id = fork();// id: 0-子进程 >0-父进程if (id == 0){while(1){printf("child process, pid: %d, ppid: %d", getpid(), getppid());sleep(1);}}else{while(1){printf("father process, pid: %d, ppid: %d", getpid(), getppid());sleep(1);}}
}

利用父子进程fork()返回值不同,达到两个死循环都在不断执行的效果:
在这里插入图片描述

通过指令查看,确实两个进程是父子进程关系:

在这里插入图片描述


下面来简要分析上面的情况,具体细节会在之后进程地址空间部分详谈。

  1. 为什么两个死循环会同时执行❓

上节讲过,进程 = 内核数据结构(PCB等)+ 可执行程序(代码+数据)。通过fork()创建子进程,肯定也要给子进程创建一个独立的task_struct,而其代码和数据指向了父进程接下来的代码和数据。子进程的大部分属性值也是由父进程拷贝而来,修改前地址不会改变。
在CPU角度,它不会管谁是父进程,谁是子进程,会在操作系统的管理下并发执行。在我们的视角下,两个死循环同时执行了。

  1. 为什么fork()返回值如此设计❓

父与子的关系是一对一或者一对多的。这样的关系导致父找子并不容易,所以创建子进程成功后需要把子进程的pid返回给父进程,方便父进程控制子进程。
而子找父是很容易的,通过系统调用getppid()即可。

  1. 为什么fork()会返回两次值❓

fork()之前只有父进程,即只有父进程才能调用fork()fork()内部在return之前肯定已经将子进程创建成功,又子进程和父进程在创建成功后代码共享,那么子进程和父进程都会执行return这条语句,这也就是为什么fork()会返回两次值。

  1. 同一个变量id怎么会既大于0,又等于0❓

进程之间具有独立性,一个进程崩溃了,不会影响另一个进程。这里的id是父子进程的共享数据,若父子进程对共享数据有写操作,这时操作系统会将该数据拷贝两份,这就是写时拷贝。那么此时,虽然这是同一个变量名,但实际上表示的是不同的值,那么id出现两种情况也就不足为奇了,实际在底层的空间根本就不是一个。

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

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

相关文章

OA办公系统自动渗透测试过程

目录 一、下载环境源码 二、部署环境 三、测试 XSS漏洞 SQL注入 文件上传漏洞 一、下载环境源码 OA源码打包地址: https://download.csdn.net/download/weixin_43650289/90434502?spm=1001.2014.3001.5503 二、部署环境

怎么修改node_modules里的文件,怎么使用patch-package修改node_modules的文件,怎么修改第三方库原文件。

在开发中会遇到需要node_modules里第三方库有bug&#xff0c;然后需要修改node_modules文件的情况 使用patch-package包可以修改node_modules里的文件 patch-package npm 官网&#xff1a;patch-package - npm 安装 npm i patch-package 修改文件后 npx patch-package s…

Python在实际工作中的运用-通用格式CSV文件自动转换XLSX

继续上篇《Python在实际工作中的运用-CSV无损转XLSX的几个方法》我们虽然对特定格式的CSV实现了快速转换XLSX的目标,但是在运行Py脚本前,还是需要编辑表格创建脚本和数据插入脚本,自动化程度很低,实用性不强,为减少人工提高效率,实现输入CSV文件路径即可自动适配完成转换…

seacmsv9报错注入

1、seacms的介绍 ​ seacms中文名&#xff1a;海洋影视管理系统。是一个采用了php5mysql架构的影视网站框架&#xff0c;因此&#xff0c;如果该框架有漏洞&#xff0c;那使用了该框架的各个网站都会有相同问题。 2、源码的分析 漏洞的部分源码如下&#xff1a; <?php …

Hbase客户端API——语句大全

目录 创建表&#xff1a; 插入数据&#xff1a; 删除数据&#xff1a; 修改数据&#xff1a; 查询数据&#xff1a;Get 查询数据&#xff1a;Scan 查询数据&#xff1a;过滤查询 创建表&#xff1a; 检验&#xff1a; 插入数据&#xff1a; 验证 一次多条数据插入 验证&…

vscode 版本

vscode官网 Visual Studio Code - Code Editing. Redefined 但是官网只提供最新 在之前的版本就要去github找了 https://github.com/microsoft/vscode/releases 获取旧版本vscode安装包的方法_vscode 老版本-CSDN博客

IP------PPP协议

这只是IP的其中一块内容PPP&#xff0c;IP还有更多内容可以查看IP专栏&#xff0c;前一章内容为网络类型&#xff0c;可通过以下路径查看IP---网络类型-CSDN博客&#xff0c;欢迎指正 3.PPP协议 1.PPP优点 网络类型&#xff1a;p2p PPP---点到点协议 兼容性会更强凡是接口或…

Springboot基础篇(3):Bean管理

前言&#xff1a;Spring 通过扫描类路径&#xff08;Classpath&#xff09;来查找带有特定注解&#xff08;如 Component、Service、Repository 等&#xff09;的类&#xff0c;并将它们注册为 Spring 容器中的 Bean。 1 Bean扫描 Bean 扫描是 Spring 框架的核心功能之一&…

Metal 学习笔记二:3D模型

是什么让一个好游戏更好玩&#xff1f;漂亮的图像&#xff01;就像《神界&#xff1a;原罪2》&#xff0c;《暗黑破坏神3》以及《巫师3》等大作一样&#xff0c;需要一个强大的程序团队以及3D美术团队强强合作。你在屏幕中看到正是3D模型使用自定义渲染绘制的结果。就像上一章你…

【算法】797. 差分

题目 797. 差分 思路 差分的实质是通过构造数组b减少时间复杂度&#xff0c;数组a为初始数据&#xff0c;构造数组b&#xff0c;数组a是b的前缀和&#xff0c;通过对数组b操作就可以实现数组a每个数加上c&#xff0c;而对数组b的操作在单位时间内即可完成&#xff0c;对数组…

解锁状态模式:Java 编程中的行为魔法

系列文章目录 后续补充~~~ 文章目录 一、状态模式&#xff1a;概念与原理二、状态模式的深度剖析&#xff08;一&#xff09;模式定义与核心思想&#xff08;二&#xff09;模式结构与角色 三、状态模式的实际应用场景&#xff08;一&#xff09;电商系统中的订单状态管理&…

php 获取head参数

php 获取head参数 在PHP中&#xff0c;获取HTTP头部&#xff08;head&#xff09;参数可以通过不同的方式实现&#xff0c;下面为你详细介绍几种常见的方法。 1. 使用$_SERVER超全局变量 $_SERVER 是PHP中的一个超全局变量&#xff0c;它包含了诸如头信息、路径、脚本位置等…

数据结构与算法-图论-最短路-拓展运用

选择最佳路线 分析&#xff1a; 这是一道图论中的最短路径问题&#xff0c;目标是在给定的公交网络中&#xff0c;找到从琪琪家附近的车站出发&#xff0c;到她朋友家附近车站&#xff08;编号为 s &#xff09;的最短时间。以下是对该问题的详细分析&#xff1a; 问题关键信息…

AI知识架构之神经网络

神经网络:这是整个内容的主题,是一种模拟人类大脑神经元结构和功能的计算模型,在人工智能领域广泛应用。基本概念:介绍神经网络相关的基础概念,为后续深入理解神经网络做铺垫。定义与起源: 神经网络是模拟人类大脑神经元结构和功能的计算模型,其起源于对生物神经系统的研…

【江科协-STM32】5. 输出比较

1. 输出比较简介 OC(Output Compare)输出比较。 输出比较可以通过CNT&#xff08;CNT计数器&#xff09;与CCR寄存器值的关系&#xff0c;来对输出电平进行置1、置0或翻转的操作&#xff0c;用于输出一定频率和占空比的PWM波形。 :::tip CNT计数器是正向计数器。它只能正向累…

C++ Primer 再探迭代器

欢迎阅读我的 【CPrimer】专栏 专栏简介&#xff1a;本专栏主要面向C初学者&#xff0c;解释C的一些基本概念和基础语言特性&#xff0c;涉及C标准库的用法&#xff0c;面向对象特性&#xff0c;泛型特性高级用法。通过使用标准库中定义的抽象设施&#xff0c;使你更加适应高级…

排查和解决线程池瓶颈问题案例

在分布式系统中&#xff0c;线程池的使用非常普遍&#xff0c;尤其是在处理异步任务时。然而&#xff0c;线程池的配置不当可能会导致性能瓶颈&#xff0c;进而影响系统的整体性能。本文将分享一个实际案例&#xff0c;介绍如何通过日志分析和线程池优化来解决系统中的性能瓶颈…

影响板材的热导率有哪些因素?

板材热导率受多种因素左右&#xff0c;可划分为内部材料特性与外部环境条件两大方面 内部材料特性 化学构成&#xff1a;不同化学元素及化合物组合形成的板材&#xff0c;热导率表现大相径庭&#xff1b;金属板材&#xff0c;像铜与铝&#xff0c;热导率优异&#xff0c;这是…

给字符串加密解密

加密规则&#xff1a;输入1a2b3c 输出 abbccc 解密&#xff1a;输入abbccc 输出 1a2b3c 代码&#xff1a; using System;namespace 加密解密 {class Program{static void Main(string[] args){Encryption("4b2a8p");Decryption("ppppppoovvv");Console.…

人工智能中的特征是什么?

什么是人工智能中的特征&#xff1f; 在人工智能中&#xff0c;特征&#xff08;feature&#xff09;是指从原始数据中提取出的、能够代表数据关键信息并用于模型训练的属性或变量。特征通常是对原始数据的抽象或转换&#xff0c;目的是捕捉数据中的模式、结构或相关性&#x…