Linux基础——进程初识(二)

1. 对当前目录创建文件的理解

我们知道在创建一个文件时,它会被默认创建到当前目录下,那么它是如何知道当前目录的呢?

对于下面这样一段代码

#include <stdio.h>
#include <unistd.h>int main()
{fopen("tmp.txt", "w");while (1){printf("这是一个进程\n");sleep(1);}return 0;
}

在它被加载成为一个进程时,我们查看相应的PID有

在Linux中所有进程是被存放在一个/proc目录中的,即

我们找到对应的PID就能进入并查看该进程,进入后发现

可以看到,在进程中有一个cwd文件,即current work dir(当前工作目录),在代码中使用fopen向磁盘中写入文件tmp.txt时,会自动的将cwd中的路径拼接到它的前面

2. 进程标识符

①PID

PID是进程标识符(Process Identifier)的缩写,它是一个唯一标识符,用于标识正在运行的每个进程。每个进程在系统中都有一个唯一的PID,可以通过PID来识别和管理进程。PID是一个非负整数,通常在系统启动时自动分配给进程,并且在一个给定的时间内是唯一的。

以以下代码为例

编译后运行有

有了标识符之后我们可以通过使用对应进程的PID使用kill命令来干掉该进程,即

kill -9 12489

那么我们如何知道当前进程的PID呢?

首先我们要知道PID是存放在task_struct中的,在我们使用ps命令时,它的本质就是遍历一遍task_struct链表,那么我们怎么获取呢——Linux肯定是不希望我们直接通过使用域访问符.来取得PID的,因此它提供了一个系统调用的接口即函数getpid(),它的手册如下

我们多运行几次后可以发现

对PID来说,PID只会保证当前运行期间有效,所以在不同的运行期间,其会不断变化

②PPID

PPID指的是父进程的PID,即父进程的进程ID号。与PID类似,要获取PPID我们也可以使用对应函数getppid(),其手册如下

在上面的多次运行中我们可以发现在不同运行期间PPID一般不变,我们查看可以发现

PID为6116的只有一个——bash,我们之前提到过,对于输入的命令,系统会单独创建一个bash来处理输入的命令,这样就能做到在输入命令时,会将其作为bash的子进程运行。而在断开主机重连后可以看到

此时PPID发生了变化,这是因为在登录到主机时,系统会单独新创建一个bash。

3. 创建进程——fork

我们以下面的代码为例

对其编译运行后我们可以使用

while :; do ps ajx | head -1 ; ps ajx | grep mycode | grep -v grep;sleep 1;done

来不断查看与mycode相关进程的状态

我们查看fork手册有

可以看到在手册中提到fork会返回两个值,返回id==0时,标识其为子进程,id>0时,标识其为父进程,而在运行结果中我们可以看到,父进程就是当前进程,子进程是新分支。至此,我们对于创建一个新进程有两种方法,其中一个就是使用./文件的方式在指令层面创建一个进程,另外一个就是使用fork函数在代码层面创建一个进程。其实在调用fork函数之后,会产生两个执行流。

在这里我们可以提出几个问题:

1. 为什么fork要给子进程返回0, 给父进程返回PID?

首先我们要知道,fork返回不同的值是为了让不同的执行流去执行不同的代码块,因为fork之后的代码是父子进程共享的,因此控制if等条件即可控制不同执行流。给子进程返回0只是一个标记,标志着子进程创建成功,而给父进程返回PID是因为对于一个父进程,其可能会有多个子进程,拿到子进程PID是为了标识唯一性。

2. fork函数是如何做到返回两次的?

首先我们要知道,创建一个子进程对于Linux来说就是创建一个新的task_struct,即只需要将原来的父进程task_struct拷贝一份,再对其中的部分属性做修改(如:PID,PPID等)即可,而在fork后父子进程访问这之后的同一份代码,因为代码不可修改,但是由于数据可能被修改,因此不能让父子进程共享同一份数据,那么就该让子进程拷贝一份父进程的数据,但是如果拷贝之后没有对数据进行修改那么又会导致资源的浪费,因此Linux规定在子进程尝试修改数据时,操作系统会为其申请一份新空间(使用多少申请多少),子进程修改这份新空间的数据即可,这样的方式也被称为数据层面的写实拷贝。

而对于fork来说,他是一个函数其内部也有其自己的实现,其内部可能包含:1. 创建子进程task_struct; 2. 填充task_struct;3. 让它指向同一份代码;4. 使它可以被自由调度;......在完成了这一系列的任务之后,子进程已经被创建好了,此时由于父子进程共享同一份代码,到最后的return 语句时,父进程与子进程会各自返回一次数据。

3. 对于id变量,它是怎么做到拥有不同内容的?

在代码中可以看到,pid_t id = fork();这个id就是数据内容,在fork返回两次后,对于id来说发生了数据的写实拷贝。

在了解了进程的创建后,我们对于bash也有了一个新的认识,即它在使用的途中一定会调用fork函数,并用其来创建子进程(执行解释命令)。

4. 进程状态

①一般操作系统学科中的进程状态

1. 运行

这些task_struct已经准备好了,可以随时被调度,此时在队列中的状态称为运行态(R),一般来说在队列中是到了谁就执行谁。那么只要进程放到CPU中,是不是一定要执行完毕所有的内容,才能执行下一个进程呢(如while(1))?答案肯定是否定的,其实对于每个进程都具有一个属性——时间片,有了时间片后,在一段时间内,所有的进程代码都会执行(并发执行)。而在这个过程中,一定会有大量的把进程从cpu上放上与拿下的动作,我们将其称为进程切换。

2. 阻塞

当task_struct对应的数据代码需要从键盘中读取数据时,但是此时却没有输入时,这种状态就称为阻塞状态,此时该task_struct会被链入键盘的waitqueue中,如果下一个需要键盘输入的task_struct直接链入之后的队列即可。

3. 挂起

在阻塞状态时,如果操作系统内部资源不足时,为了保证操作系统维持正常状态而要省出资源,此时操作系统会将task_struct保留,将代码和数据放在外设中(换出),此时的进程状态为挂起,而在需要时会将代码和数据加载回来(换入)。

②Linux中的进程状态

在Linux中定义如下

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

以下面的代码为例

我将其运行后查看

此时的S+(此处的+表示前台运行,不能输入bash命令)表示处于S状态(即阻塞状态),这是因为cpu的运行速度太快,而显示屏运行速度相等较慢,因此有极大的可能性时处于S状态,而我们将代码修改一下

,即可发现

此时,由于不需要等待外设,因此一直处于运行态即R。

对于D状态,我们先举一个具体的例子,

若处于极端情况下时,进程被kill,磁盘写入数据失败时,反馈信息给进程时,进程却不见了,此时磁盘一般会选择丢失这部分数据,那么为了防止这种情况发生,我们只需要让进程在等待磁盘时,不能被杀掉即可,即将其设置为D状态,在磁盘写入完毕后再将其状态修改为S。由此,我们可以认识到S状态属于浅度睡眠,可以随时响应系统的调度,而D状态属于深度睡眠,它不会响应系统调度。

对于T状态,我们可以使用kill的命令来暂停进程,即

查看后,我们知道可以使用-19命令来发出暂停信号, 即

此时我们可以看到mycode处于暂停状态,而对于t状态,我们可以使用gdb来演示

可以看到,当我们使用断点停止在某一处时,此时mycode处于t状态。

对于X状态和Z状态,在一个进程死亡的时候,会先进入Z状态,其目的是需要维持相应的状态,直到被父进程读取到信息后,其状态才会转换成X(瞬时)。

我们以下面的代码举例

运行并监视有

可以看到,在子进程结束,父进程未结束后,子进程处于Z+状态<defunct>(失效的),我们将此状态称为僵尸状态,进程一般退出时,若父进程没有主动回收子进程信息,子进程会一直处于Z状态,这样就会导致资源会被一直占用,就有可能导致内存泄漏。

将代码修改一下

运行并监视有

可以看到,对于操作系统本身来说,若父进程先退出,其子进程的父进程会被修改为1号进程(即操作系统)。孤儿进程会在后台运行,而且因为其父进程存在,不会变成僵尸进程即不会造成内存泄漏。对于父进程为1的进程我们将其称为孤儿进程,该进程被操作系统所领养。那么为什么要被领养呢?因为孤儿进程未来也要退出,也需要被释放,而操作系统本身具有回收功能。

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

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

相关文章

WPF 新手指引弹窗

新手指引弹窗介绍 我们在第一次使用某个软件时&#xff0c;通常会有一个“新手指引”教学引导。WPF实现“新手指引”非常方便&#xff0c;且非常有趣。接下来我们就开始制作一个简单的”新手指引”(代码简单易懂&#xff0c;便于移植)&#xff0c;引用到我们的项目中又可添加一…

钡铼技术2023年年度报告来了

不积跬步&#xff0c;无以至千里&#xff1b; 不积小流&#xff0c;无以成江海。 钡铼的2023年 平凡却又意义深远。 在工业自动化及物联网技术发展的道路上&#xff0c;钡铼技术每一个进步都源于不懈的努力和持续的积累。钡铼技术在过去的一年中&#xff0c;稳扎稳打&#xf…

Redis高级特性和应用(慢查询、Pipeline、事务、Lua)

Redis的慢查询 许多存储系统(例如 MySQL)提供慢查询日志帮助开发和运维人员定位系统存在的慢操作。所谓慢查询日志就是系统在命令执行前后计算每条命令的执行时间,当超过预设阀值,就将这条命令的相关信息(例如:发生时间,耗时,命令的详细信息)记录下来,Redis也提供了类似…

剧本杀小程序/APP搭建,增加玩家游戏体验

近年来&#xff0c;剧本杀游戏成为了年轻人娱乐的新方式&#xff0c;受到了年轻人的追捧。 剧本杀是一种新型的社交游戏&#xff0c;在游戏中&#xff0c;玩家不仅可以进行角色扮演&#xff0c;也能够交到好友&#xff0c;符合当下年轻人的生活模式。 小程序、app是当下剧本杀…

【计算机毕业设计】python+django数码电子论坛系统设计与实现

本系统主要包括管理员和用户两个角色组成&#xff1b;主要包括&#xff1a;首页、个人中心、用户管理、分类管理、数码板块管理、数码评价管理、数码论坛管理、畅聊板块管理、系统管理等功能的管理系统。 后端&#xff1a;pythondjango 前端&#xff1a;vue.jselementui 框架&a…

UntiyShader(七)Debug

目录 前言 一、利用假彩色图像 二、利用Visual Studio 三、帧调试器 前言 Debug&#xff08;调试&#xff09;&#xff0c;是程序员检查问题的一种方法&#xff0c;对于一个Shader调试更是一种噩梦&#xff0c;这也是Shader难写的原因之一——如果效果不对&#xff0c;我们…

外包干了4个月,技术退步明显了...

先说一下自己的情况&#xff0c;大专生&#xff0c;18年通过校招进入武汉某软件公司&#xff0c;干了接近4年的功能测试&#xff0c;今年年初&#xff0c;感觉自己不能够在这样下去了&#xff0c;长时间呆在一个舒适的环境会让一个人堕落&#xff01; 而我已经在一个企业干了四…

SQL 在已有表中修改列名的方法

文章目录 1. MySQL2. SQL Server3. Oracle / PostgreSQL Question&#xff1a; 假设有一张表 StudentInfo&#xff0c;表中有一个列名是 Student_Name &#xff0c;想要把这个列名改成 StudentName 应该如何操作&#xff1f; 建表语句如下&#xff1a; --建表 if object_id(S…

linux(centos)相关

文件架构&#xff1a; bin--binary--二进制命令&#xff0c;可直接执行 sbin systembin系统二进制命令&#xff0c;超级管理员 lib 库目录 类似dll文件 lib64 64位系统相关的库文件 usr 用户文件 boot 引导分区的文件&#xff0c;链接&#xff0c;系统启动等 dev device设备目录…

前端--基础 常用标签-超链接标签 外部链接( herf 和 target)

目录 超链接标签 &#xff1a; 超链接的语法格式 &#xff1a; 超链接的属性 &#xff1a; 超链接的分类 &#xff1a; 外部链接 &#xff1a; 超链接标签 &#xff1a; # 在 HTML 标签中&#xff0c;<a> 标签用于定义超链接&#xff0c;作用是从一个页面…

第13课 利用openCV检测物体是否运动了

FFmpeg与openCV绝对是绝配。前面我们已经基本熟悉了FFmpeg的工作流程&#xff0c;这一章我们重点来看看openCV。 在前面&#xff0c;我们已经使用openCV打开过摄像头并在MFC中显示图像&#xff0c;但openCV能做的要远超你的想像&#xff0c;比如可以用它来实现人脸检测、车牌识…

【Unity嵌入Android原生工程】

Unity嵌入Android原生工程 本章学习,Unity模块嵌入Android## 标题Unity导出Android工程创建Android Studio工程Unity嵌入到Andorid StudioAndroid原生代码跳转到Unity场景工作需要嵌入原生工程,并实现热更,记录一下 工具,Unity2023.3.14,Android Studio 2022.3.1 patch3 Un…

JVM知识总结(简单且高效)

1. JVM内存与本地内存 JVM内存&#xff1a;受虚拟机内存大小的参数控制&#xff0c;当大小超过参数设置的大小时会报OOM。本地内存&#xff1a;本地内存不受虚拟机内存参数的限制&#xff0c;只受物理内存容量的限制&#xff1b;虽然不受参数的限制&#xff0c;如果所占内存超过…

网络安全红队常用的攻击方法及路径

一、信息收集 收集的内容包括目标系统的组织架构、IT资产、敏感信息泄露、供应商信息等各个方面&#xff0c;通过对收集的信息进行梳理&#xff0c;定位到安全薄弱点&#xff0c;从而实施下一步的攻击行为。 域名收集 1.备案查询 天眼查爱企查官方ICP备案查询 通过以上三个…

抖店入驻条件是什么?需要多少费用?

我是电商珠珠 新手入驻抖店最关心的就是抖店的入驻条件&#xff0c;以及费用&#xff0c;今天我就来给大家详细的讲一下。 入驻条件 1、营业执照 入驻抖店新手需要准备一张个体工营业执照&#xff0c;在办理营业执照的时候要办理全类目的&#xff0c;我这里有份全类目营业执…

云服务器安装mysql全流程

一、下载安装包 官网链接&#xff1a;MySQL :: Download MySQL Community Server 选择适合自己版本和操作系统 二、安装包上传服务器 在本地终端执行scp命令 三、服务器上使用安装包 卸载旧版本 #检查是否之前安装过mysql服务 [lighthouseVM-24-3-opencloudos software]# r…

Pytest——Fixture夹具的使用

一、什么是Fixture 在测试开展的过程中&#xff0c;会需要考虑到测试前的准备工作&#xff0c;以及测试后的释放操作行为。这些在Pytest中&#xff0c;会通过Fixture的方式来实现。如果说在运行pytest的测试用例的时候&#xff0c;需要调用一些数据来实现测试行为&#xff0c;…

用友U8 Cloud smartweb2.RPC.d XML外部实体注入漏洞

产品介绍 用友U8cloud是用友推出的新一代云ERP&#xff0c;主要聚焦成长型、创新型、集团型企业&#xff0c;提供企业级云ERP整体解决方案。它包含ERP的各项应用&#xff0c;包括iUAP、财务会计、iUFO cloud、供应链与质量管理、人力资源、生产制造、管理会计、资产管理&#…

企业出海数据合规:GDPR中的个人数据与非个人数据之区分

GDPR仅适用于个人数据&#xff0c;这意味着非个人数据不在其适用范围内。因此&#xff0c;个人数据的定义是一个至关重要的因素&#xff0c;因为它决定了处理数据的实体是否要遵守该法规对数据控制者规定的各种义务。尽管如此&#xff0c;什么是个人数据仍然是当前数据保护制度…

万众期盼的剪辑新功能来了 会声会影2024旗舰版焕新登场

会声会影2024全新升级来袭&#xff0c;Corel公司这次为用户带来了多项功能更新&#xff0c;软件风格整体更偏向于“轻松剪辑&#xff0c;快速出片”。会声会影的本次更新还是很令人惊喜的&#xff0c;在各种人工智能算法的加持下&#xff0c;用户只需要进行几步简单地设置&…