【Linux探索学习】第十二弹——初识进程:进程的定义、描述和一些简单的相关操作

news2024/12/26 11:14:48

Linux学习笔记:

https://blog.csdn.net/2301_80220607/category_12805278.html?spm=1001.2014.3001.5482

前言:

在前面经过那么多篇的铺垫后,今天我们正式进入Linux学习的第一个重难点——进程,理解进程对于我们学习操作系统的其它部分,尤其是多文件处理和资源管理十分重要,下面我们正式进入进程的第一篇讲解

目录

一、进程概念

二、进程描述

三、查看进程

四、通过系统调用获取进程标识符

五、通过系统调用创建进程——初识fork

六、总结


一、进程概念

进程是一个正在执行的程序的实例。它不仅包括程序的代码,还包括程序的当前活动、寄存器、程序计数器、堆栈及其所有与执行相关的资源。简单来说,进程是一个程序在运行时的一个动态实体。

需要注意的一点是进程的程序是一定被加载在内存中的,因为进程是系统将要进行处理的数据,而CPU是从内存中获取数据的,所以说进程的程序一定被加载在内存中的,比如我们vim写的一个.c的C语言程序,它在操作系统下的本质就是一个文件,是存放在外设中的,当运行起来时,我们就会将它的相关数据存放到内存中去,以便于CPU直接获取

二、进程描述

一个操作系统可能可以同时进行多个进程,比如我们可以让多个程序同时进行,我们的电脑可以同时跑多个软件,为了避免进程执行起来互相干扰,所以我们要对进程进行管理

一般进行管理的过程就是:先描述+再组织

所以我们要进行进程描述:任何一个进程,在被加载到内存,形成真正的进程时,操作系统都要先创建描述进程的结构体对象——PCB,也叫做进程控制块,可以理解为进程属性的集合,操作系统是C语言写的,所以PCB一定是一个struct结构体,PCB中会包含进程如下的重要信息:

  • 进程ID(PID):唯一标识一个进程的编号。
  • 进程状态:当前进程的状态。
  • 程序计数器:指向当前执行指令的地址。
  • CPU寄存器:进程在执行时的寄存器内容。
  • 内存管理信息:如页表和段表。
  • 进程优先级:调度时的优先级信息。

此外为了方便管理进程,处理进程与进程之间的关系,进程在内存中是以队列的形式存在的,具体点来讲就是链表(双链表),进程在内存中的存在形式可以抽象为下图:

由于PCB中包含着进程的所有信息,所以对进程管理的本质其实就是对进程的PCB做管理,进程在操作系统又通过队列进行链接,所以对进程的管理,其实就是对链表的增删改查

这里的PCB是针对所有操作系统而言的,在我们的Linux中我们往往习惯称呼这个概念为task struct

三、查看进程

在上面我们讲到进程的许多属性,包括进程编号、进程状态等等许多内容

首先我们可以通过查看/proc/文件,来查看我们目前正在执行的全部进程

ls /proc/

这些数字就是进程的PID,每个进程都会有一个对应的PID,PID就是我们上面所说的进程ID,也叫做进程标识符,我们可以通过这些进程标识符来查看每个进程具体的信息,比如查看1号进程

ls /proc/1

除了上面的这个方法外,我们还可以通过下面这个指令,不仅可以看到所有的进程,还可以看到它们的进程的属性信息:

ps axj

我们节选一部分:

执行结果的第一行就是我们的进程属性信息的列名,下面就是每个进程对应的属性信息,我们可以只打印出一行来看一下进程属性的内容(需要借助之前的知识:管道 | 和打印行数head)

ps axj | head -1

对于这些属性信息中,我们先记住前两个就行了,PPID指的是父进程标识符,PID知道是当前进程标识符

目前我们自己创建的可执行文件有test

我们可以查看下我们自己创建的这个进程的相关信息(注意只有当我们的程序在跑着的时候它才叫进程,所以我们可以将我们的程序写成一个死循环,然后让它执行起来)

ps axj | head -1 && ps axj | grep test

观察这个执行结果,我们可以发现有两个相关进程,会出现第二条的原因就是执行查找test进程的命令本身也会成为一个进程,而这个进程中含test,所以会把自身也带上

如果不想要,可以在后面加上 | grep -v grep,这个-v选项我们在前面讲指令的时候是讲过的,是反向匹配的意思

ps axj | head -1 && ps axj | grep test | grep -v grep

四、通过系统调用获取进程标识符

除了上面获取进程标识符的方法外,我们还可以通过系统调用的方式来获取表示符,系统接口为getpid和getppid,我们可以通过man手册来查看这个接口

man 2 getpid

具体方法如下:

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

多次执行这个程序,我们会发现pid一直在变化,而ppid一直不变,也就是说子进程编号一直在变化,而父进程一直没变,为什么会出现这个现象呢?

这是因为,我们在打开Linux时,会首先创建一个bash进程,形成对话框,这个bash进程也是其它所有进程的子进程,所以一般代码重新运行时,它的子进程编号会变,而父进程编号不会变


我们可以创建一个监视窗口方便观察(了解):

while :; do ps axj | head -1 ; ps axj | grep test | grep -v grep; 
echo "----------------------------"; sleep 1 ; done

五、通过系统调用创建进程——初识fork

我们可以通过fork手动创建进程,我们可以通过man手册查看一下fork

man fork

我们先来看下面的一个小程序:

#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>

int main()
{
     printf("before test");
     fork();
     printf("after test");
     return 0;
}

运行结果:

我们注意到在fork()函数之后的第二行打印语句执行了两次,说明在fork()之后一个进程变成了两个进程

此外,fork函数还有一个重要知识就是它是有两个整形返回值的,这点与我们之前所学的C语言中的函数差别很大,因为我们之前所学的函数都是只有一个返回值,fork的两个整形返回值中,大于0代表父进程,等于0是子进程

我们下面来看这样一个程序来验证一下:

  1 #include<stdio.h>
  2 #include<sys/types.h>
  3 #include<unistd.h>
  4  
  5 int main()
  6 {
  7     pid_t id=fork();
  8     if(id>0)
  9     {
 10         //父进程
 11         printf("I am parent process, pid:%d, ppid:%d\n",getpid(),getppid());
 12     }
 13     else if(id==0)
 14     {
 15         //子进程
 16         printf("I am child process, pid:%d, ppid:%d\n",getpid(),getppid());
 17     }
 18     printf("hello linux\n");
 19     return 0;
 20 }

在这个函数中我们尝试将父子进程分开,并且在最后有一个公共代码区,执行结果:

我们可以看到子进程的ppid就是父进程的pid,所以也印证了它们的父子关系,而且最后一个打印代码父子进程都执行了

相信不少同学对上面的问题已经有了很大的疑惑了,比如fork为什么要给子进程返回0,给父进程返回子进程pid呢?其实这就是为了区分父子进程,让不同的执行流执行不同的代码

一般而言fork之后的代码是共享的,这也就是为什么上面的  "hello linux"  打印了两遍的原因,因为父子进程都执行了它,那么如果此时子进程对共享数据进行操作了,我们就需要对额外操作的数据开辟新空间,这就是写时拷贝,这我们会在后面详细讲解

至于为何pid_t id中的id可以取两个值,这也需要我们后面讲到进程空间地址的问题时再提,现在只需要也简单地理解为写时拷贝就可以了

六、总结

以上就是今天讲解的进程的基础内容,篇幅较长,文字较多,相信认真看完的你会有所收获,后面我们就将开启进程知识的深度讲解


感谢各位大佬观看,创作不易,还请各位大佬点赞支持!!!

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

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

相关文章

AI教育革命:个性化学习的新篇章

内容概要 在 教育 领域&#xff0c;人工智能 的崭露头角带来了前所未有的变化。如今&#xff0c;个性化学习 已不再是一个遥不可及的梦想&#xff0c;而是通过 AI 技术真正实现的可能。借助先进的数据分析能力&#xff0c;教师可以实时跟踪和评估每位学生的学习进度&#xff0…

ASMR助眠声音视频素材去哪找 吃播助眠素材网站分享

在快节奏的现代生活中&#xff0c;越来越多的人感到压力山大&#xff0c;许多人开始寻求助眠和放松的方式。而ASMR&#xff08;自发性知觉经络反应&#xff09;助眠声音视频&#xff0c;凭借其独特的声音刺激和放松效果&#xff0c;成为了睡前的“神器”。如果你是一位内容创作…

项目管理中不可或缺的能力

在现代企业中&#xff0c;项目管理是一项至关重要的能力。项目管理需要具备的能力包括&#xff1a;有效的沟通能力、团队协作能力、时间管理能力、风险管理能力、以及问题解决能力。 其中&#xff0c;有效的沟通能力尤为重要&#xff0c;它不仅涉及到信息的传递&#xff0c;还包…

蓝桥杯备考——算法

一、排序 冒泡排序、选择排序、插入排序、 快速排序、归并排序、桶排序 二、枚举 三、二分查找与二分答案 四、搜索&#xff08;DFS&#xff09; DFS&#xff08;DFS基础、回溯、剪枝、记忆化&#xff09; 1.DFS算法&#xff08;深度优先搜索算法&#xff09; 深度优先搜…

【Vue】Vue3.0(十九)Vue 3.0 中一种组件间通信方式-自定义事件

文章目录 一、自定义事件概念及使用场景二、代码解释三、新的示例 一、自定义事件概念及使用场景 概念 在 Vue 3.0 中&#xff0c;自定义事件是一种组件间通信的机制&#xff0c;允许子组件向父组件传递数据或触发父组件中的操作。子组件通过defineEmits函数定义可以触发的事件…

成功解决WSL2上的Ubuntu22.04执行sudo apt-get update指令报错问题

问题&#xff1a;输入sudo apt-get update指令会显示如下报错 问题所在&#xff1a;Temporary failure in name resolution 显然是系统无法解析域名。这可能是 DNS 配置问题。 解决方案&#xff1a; 临时修改 DNS 配置 尝试手动修改 /etc/resolv.conf 文件来使用公共 DNS 服务…

L1G3000 提示工程(Prompt Engineering)

什么是Prompt(提示词)? Prompt是一种灵活、多样化的输入方式&#xff0c;可以用于指导大语言模型生成各种类型的内容。什么是提示工程? 提示工程是一种通过设计和调整输入(Prompts)来改善模型性能或控制其输出结果的技术。 六大基本原则: 指令要清晰提供参考内容复杂的任务拆…

探索Python的Shell力量:Plumbum库揭秘

文章目录 探索Python的Shell力量&#xff1a;Plumbum库揭秘第一部分&#xff1a;背景介绍第二部分&#xff1a;Plumbum是什么&#xff1f;第三部分&#xff1a;如何安装Plumbum&#xff1f;2. 创建管道3. 重定向4. 工作目录操作5. 前台和后台执行 第五部分&#xff1a;场景应用…

点击文本将内容填入tinymce-vue 富文本编辑器的光标处

富文本编辑器组件 <template><div ref"tinymceBox" class"tinymce-box"><Editor id"myEditor" v-model"contentValue" :init"init" :disabled"disabled" blur"inputBlur" click"o…

星海智算:风月ComfyUI_SD3.5

&#xff08;一&#xff09;镜像介绍 1、风月ComfyUI_SD3.5​ 占用69.71G磁盘&#xff0c;为用户预留了近30个G使用。 2、SD3.5​ SD3.5&#xff0c;即Stable Diffusion 3.5&#xff0c;是Stability AI推出的最新图像生成模型&#xff0c;是Stable Diffusion 3.0版本的升级版…

在模方置平建筑失败的原因是什么?

在模方置平建筑失败的原因是什么&#xff1f; 可能是obj拓扑不连续&#xff0c;可以在网格大师使用osgb转obj功能&#xff0c;选择拓扑或者重建。 网格大师是一款能够解决实景三维模型空间参考、原点、瓦块大小不统一&#xff0c;重叠区域处理问题的工具“百宝箱”&#xff0c…

python 语言入门

目录 1.发展历程 2.优缺点 3.环境搭建 3.1.Anaconda 3.2.VSCode 3.3.重装自己的独立环境 4.第一个 python 程序 4.1.创建一个 .py 的文件 4.2.编写 python 代码 ​4.3.运行 python 代码 5.注释 5.1.单行注释 5.2.多行注释 6.转义字符 7.变量 7.1.变量类型 7.2…

C++11 --- 智能指针详解

C11 智能指针 一、智能指针的使用场景分析二、RAII和智能指针的设计思路三、智能指针的本质及衍生的问题四、C标准库的智能指针的使用五、智能指针的原理&#xff08;模拟实现&#xff09;1. auto_ptr的模拟实现2. unique_ptr的模拟实现3. shared_ptr的模拟实现&#xff08;简单…

(实战)WebApi第13讲:怎么把不同表里的东西,包括同一个表里面不同的列设置成不同的实体,所有的给整合到一起?【前端+后端】、前端中点击标签后在界面中显示

一、实现全局跨域&#xff1a;新建一个Controller&#xff0c;其它的controller都继承它 1、新建BaseController 2、在后端配置&#xff0c;此处省略【详情见第12讲四、3、】 3、其它的控制器继承BaseController&#xff0c;这个时候就能够完成全局的跨域 【向后台传cookie和…

【C++】map和set的介绍及使用

前言&#xff1a; map和 set 是 C STL&#xff08;标准模板库&#xff09;中的两种非常重要的容器&#xff0c;它们基于一种叫做平衡二叉搜索树&#xff08;通常是红黑树&#xff09;的数据结构来实现。在 C 中&#xff0c;map 是一个键值对容器&#xff0c;set 只存储唯一的键…

Python的函数(补充浅拷贝和深拷贝)

一、定义 函数的定义&#xff1a;实现【特定功能】的代码块。 形参&#xff1a;函数定义时的参数&#xff0c;没有实际意义 实参&#xff1a;函数调用/使用时的参数&#xff0c;有实际意义 函数的作用&#xff1a; 简化代码提高代码重用性便于维护和修改提高代码的可扩展性…

el-input 正则表达式校验输入框不能输入汉字

<el-form :model"data1" :rules"rules" ref"ruleForm" label-width"210px" class"demo-ruleForm"><el-form-item label"锯路&#xff1a;" prop"sawKref"><el-input class"inptWid…

嵌入式linux系统中I2C控制实现AP3216C传感器方法

大家好,今天主要给大家分享一下,如何使用linux系统里面的I2C进行控制实现。 第一:Linux系统中I2C简介 Linux 内核开发者为了让驱动开发工程师在内核中方便的添加自己的 I2C 设备驱动程序,更容易的在 linux 下驱动自己的 I2C 接口硬件,进而引入了 I2C 总线框架。与 Linux 下…

OceanBase 应用实践:如何处理数据空洞,降低存储空间

问题描述 某保险行业客户的核心系统&#xff0c;从Oracle 迁移到OceanBase之后&#xff0c;发现数据存储空间出现膨胀问题&#xff0c;数据空间 datasize9857715.48M&#xff0c;实际存储占用空间17790702.00M。根据 required_mb - data_mb 值判断&#xff0c;数据空洞较为严重…

【flask开启进程,前端内容图片化并转pdf-会议签到补充】

flask开启进程,前端内容图片化并转pdf-会议签到补充 flask及flask-socketio开启threading页面内容转图片转pdf流程前端主js代码内容转图片-browser端browser端的同步编程flask的主要功能route,def 总结 用到了pdf,来回数据转发和合成,担心flask卡顿,响应差,于是刚好看到threadi…