【Linux进程篇3】说白了,Linux创建进程(fork父子进程)也就那样!!!

---------------------------------------------------------------------------------------------------------------------------------

每日鸡汤:没人可以好运一生,只有努力才是一生的护身符,不放弃、不辜负。

---------------------------------------------------------------------------------------------------------------------------------

目录

前言

一:前期知识铺垫

1.1:查看/杀死进程指令

1.1.1:查看进程指令

1.1.2:杀死进程指令

1.2:获取进程PID(编号标识符)

1.2.1:while循环监视脚本

1.2.2:获取进程PID

1.3:获取进程的父进程编号标识符(PPID)

1.4:总结

二:父进程fork创建子进程

三:创建进程需要打败的四个怪兽(问题)

3.1:怪兽一:为什么fork要给子进程返回0,给父进程返回子进程的PID?

3.2:怪兽二:fork函数究竟在干什么?干了什么?

3.3:怪兽三:一个函数是如何返回2次的?如何理解?

3.4:怪兽四:一个变量怎么会有两个不同的内容?如何理解?


前言

根据前篇文章,我们已经了解了操作系统通过先描述再组织来对进程进行管理。描述进程操作系统自动生成task_struct结构体,组织进程将多个task_struct结构体对象”链起来“形成数据结构,这样对进程的管理就变成了对链表的增删改查

一:前期知识铺垫

1.1:查看/杀死进程指令

1.1.1:查看进程指令

ps ajx:查看所有的进程;

ps ajx | grep pro:只查看名为pro的进程

ps ajx | head -1 ; ps ajx | grep pro:查看pro进程的时候将最开始的那一列名称显示出来。

多行指令并行起来【;  &&】:

所以将 ps ajx | head -1 指令和 ps ajx | grep pro指令并行起来:

法一:ps ajx | head -1 && ps ajx | grep pro

法二:ps ajx | head -1 ; ps ajx | grep pro

1.1.2:杀死进程指令

但是发现有多余的进程——grep --color=auto pro;这是因为grep”关键字过滤“,要过滤名为pro的进程,前提就是将grep指令运行起来,一旦被运行起来,grep就也被加载到了内存当中了,形成进程。那么如何将它给取消(杀)掉呢?

杀死进程的两种方式:

法一:grep -v grep【ps ajx | head -1 && ps ajx | grep pro | grep -v prep

法二:kill -9 该进程的PID编号【常用】

1.2:获取进程PID(编号标识符)

1.2.1:while循环监视脚本

while :; do echo "Hello Linux"; sleep 1; done

while循环打印Hello Linux,每间隔1秒打印一次。

每间隔1秒获取一个进程 ,用来监视进程情况。

while :; do ps ajx | head -1 ; ps ajx | grep pro | grep -v grep; echo "----------------------"; sleep 1; done

开始时没有进程,之后运行可执行程序pro进程时,立刻就出现了./pro进程了

1.2.2:获取进程PID

PID也是task_struct内部的属性之一。通过getpid函数获取该进程的PID编号

看例子:查看getpid函数用法:man getpid

pro.c文件内部

 看运行情况:

1.3:获取进程的父进程编号标识符(PPID)

PPID:该进程父进程的PID。

getppid函数:获取当前进程的父进程PID。

查看getppid函数的用法:man getppid

验证情况:

pro.c文件内部:

 运行情况:

 那么该进程的父进程到底是什么?

查看父进程:ps ajx | head -1 ; ps ajx | grep 4901 | grep -v grep

 该进程的父进程是bash进程。bash进程的PID=4901

1.4:总结

  1. 进程的PCB数据结构体中含有一系列属性,例如PID和PPID就是PCB数据结构体中的属性。
  2. 通过系统调用接口使用getpid()方法获取某一个进程的PID,使用getppid()方法来获取该进程的PPID(父进程PID)
  3. 发现,无论我们怎样操作进程,父进程PPID总是不变的(除了重新登陆xshell)
  4. 查看父进程:ps ajx | head -1 ; ps ajx | grep 21823(该进程的PPID)=> bash进程,PID = 21823,即该进程是通过bash进程创建出来的【使用fork函数】
  5. 每次登录xshell的时候,系统就会创建一个新的bash进程,所以每一次的bash进程的PID可能会不同=> 在终端上输入的所有进程都是bash的子进程。

二:父进程fork创建子进程

fork函数手动创建进程:

fork函数创建进程成功,会返回两个值。

pro.c文件

#include<stdio.h>
#include<unistd.h>
#include <sys/types.h>int main()
{printf("begin:我是一个进程,pid:%d, ppid:%d\n",getpid(),getppid());pid_t id = fork();sleep(1);if(id == 0){//子进程printf("子进程id = %d\n",id);while(1){printf("我是一个子进程,pid: %d, ppid: %d\n",getpid(),getppid());sleep(1);}}else if (id > 0){//父进程printf("父进程id = %d\n",id);while(1){printf("我是一个父进程,pid: %d, ppid: %d\n",getpid(),getppid());sleep(1);}}else {//错误,error}return 0;
}

编译运行情况: 

 执行流,是从上往下依次进行的。

  1. 并且fork函数给父进程返回子进程的PID,给子进程返回0。为什么?
  2. fork函数到底干了什么使得一个id进入了两个循环。
  3. fork函数怎么能够返回两次的。为什么?
  4. 发现一个id变量竟然可以有两个值。为什么?

三:创建进程需要打败的四个怪兽(问题)

3.1:怪兽一:为什么fork要给子进程返回0,给父进程返回子进程的PID?

答:返回不同的返回值,是为了区分让不同的执行流执行不同的代码块。即,可以通过fork返回值明确访问哪一个子进程。

一般而言,fork之后的代码块”父子共享“。

#include<stdio.h>
#include<unistd.h>
#include <sys/types.h>int main()
{printf("begin:我是一个进程,pid:%d, ppid:%d\n",getpid(),getppid());pid_t id = fork();printf("检测父进程和子进程代码共享\n");    sleep(1);if(id == 0){//子进程printf("子进程id = %d\n",id);while(1){printf("我是一个子进程,pid: %d, ppid: %d\n",getpid(),getppid());sleep(1);}}else if (id > 0){//父进程printf("父进程id = %d\n",id);while(1){printf("我是一个父进程,pid: %d, ppid: %d\n",getpid(),getppid());sleep(1);}}else {//错误,error}return 0;
}

若fork之后的代码父子共享,那么”检测父进程和子进程代码共享“这句话会执行两次!!!

3.2:怪兽二:fork函数究竟在干什么?干了什么?

知道:

进程 = 内核数据结构(PCB/task_struct) + 代码和数据

所以, fork创建子进程的本质:系统中多了一个进程(PCB / task_struct)。并且,通过fork创建的子进程以父进程为模板,在对应的属性(pid,ppid,...)进行一些修改来创建的一个新的进程。

 fork之后,父子进程之后代码是共享的。且,在代码加载到内存中之后,代码是不可修改的,即内存中的代码是不可被修改的。

那么fork函数之后,父子代码是共享的,那么数据呢?=>问题四解决。

我们为什么要创建子进程呢?最主要的目的就是需要想办法让父与子进程执行不同的代码块(让fork具有不同的返回值)。

3.3:怪兽三:一个函数是如何返回2次的?如何理解?

首先说明,fork也是一个函数。并且因为父子进程代码是共享的。

 因为父子进程都是独立的task_struct,都是可以被CPU调度运行的。

return ret;  :也是代码,也是属于父与子共享的【父进程返回一个ret,子进程返回一个ret】

所以一个函数返回了2次的。

3.4:怪兽四:一个变量怎么会有两个不同的内容?如何理解?

我们已经知道通过fork函数是可以返回2次的。那么一个id变量怎么会有不同的内容?

一个学习知识点:进程是具有独立性的!!!

任何平台,进程在运行的时候,是具有独立性的【例如,关闭酷狗音乐进程,并不影响xshell进程...】,即一个进程退出崩溃不影响另一个进程。

因为父进程和子进程属于两个进程,两个进程各自具有独立性!

那么如何看待进程中【代码和数据】中的数据?答:因为在内存中的数据可能被修改,所以为了保证父子的独立性,就不能让父进程和子进程共享同一份数据!!!

父进程的数据是原有的数据,那么子进程的数据呢

理论情况下:操作系统会单独的拷贝父进程的数据,在粘贴到另外内存中开辟的空间,作为子进程的数据!

但是,实际上数据层面会发生写时拷贝【用多少,给多少空间】(达到节省空间的目的)

步骤如下:

首先,父进程和子进程同时指向相同的代码和数据。之后父进程和子进程进行后续代码的共享。但是当子进程想对数据(共享的某一数据)进行修改时,操作系统为了保证进程的独立性,会进行拦截(将子进程要修改数据的要求进行拦截),此时操作系统将要修改的数据变量那一部分(id变量)重新在内存中开辟合适的新空间,将该变量放入新建空间中,该新建空间独属于子进程。这样就只开辟一个4字节的空间即可。子进程修改多少数据,就创建多大的空间。

写时拷贝 

fork函数的 return 过程的时候,是写入吗? 

  • pid_t id = fork();
  • 在父进程 return 时,id就是父进程的数据
  • 在子进程 return 时,操作系统写时拷贝,在新空间内定义一个新的id变量【独属于子进程的id】

如果父子进程被创建好,fork()往后,谁先运行呢?

关于谁先运行,由调度器【将进程调度到CPU中】决定,是不确定的,在内存中,有许多的进程,各个进程都要进入到CPU中执行,各个进程就是竞争关系,为了避免一个进程被调用多次,而另一个进程一次也没有被调用过,这就需要有调度器(保证进程之间公平)。

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

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

相关文章

使用服务器时进行深度学习训练时,本地必须一直保持连接状态吗?

可以直接查看方法&#xff0c;不看背景 1.使用背景2. 方法2.1 screen命令介绍2.2 为什么要使用screen命令2.3 安装screen2.4 创建session2.5 查看session是否创建成功2.6 跳转进入session2.7 退出跑代码的session2.8 删除session 1.使用背景 我们在进行深度学习训练的时候&…

防火墙笔记地十二天

1.IPSEC协议簇 IPSEC协议簇 --- 基于网络层的&#xff0c;应用密码学的安全通信协议组 IPV6中&#xff0c;IPSEC是要求强制使用的&#xff0c;但是&#xff0c;IPV4中作为可选项使用 IPSEC可以提供的安全服务 机密性 --- 数据加密 完整性 --- 防篡改 可用性 数据源鉴别 -…

即时设计:Sketch的云端版本控制

设计师们经常面临的一个挑战是设计软件的频繁更新&#xff0c;尤其是Sketch这类流行工具。每次更新可能会修复一些旧bug并增加新功能&#xff0c;但同时也可能导致与旧版本的不兼容问题&#xff0c;尤其是在不同工作环境中的电脑性能差异可能导致文件兼容性问题。那么&#xff…

什么是网络安全CTF有何意义?该如何入门?

什么是网络安全CTF?有何意义 &#xff1f;该如何入门 &#xff1f; 什么是网络安全CTF? CTF在网络安全领域中指的是网络安全技术人员之间进行技术竞技的一种比赛形式。它起源于1996年DEFCON&#xff0c;以代替之前通过互相发起真实攻击进行技术比拼的方式。发展至今&#xff…

【Window主机访问Ubuntu从机——Xrdp配置与使用】

使用Xrdp在Window环境下远程桌面访问Ubuntu主机 文章目录 Ubuntu安装图形化界面Ubuntu安装Xrdp通过网线连接两台主机Window主机有线连接配置Ubuntu从机设置测试有线连接 Window主机打开远程桌面功能参考文章总结 Ubuntu安装图形化界面 sudo apt update sudo apt upgrade sudo …

Python-基础语法·上(2)

目录 常量和表达式 变量的语法 定义变量 使用变量 变量的类型 整型与浮点型 字符串 布尔 为什么要有这么多类型? 动态类型特性 注释 输入输出 通过控制台输出 通过控制台输入 运算符 算术运算符 关系运算符 逻辑运算符 赋值运算符 其他 python的一些小练…

【go从零单排】panic、recover、defer

&#x1f308;Don’t worry , just coding! 内耗与overthinking只会削弱你的精力&#xff0c;虚度你的光阴&#xff0c;每天迈出一小步&#xff0c;回头时发现已经走了很远。 &#x1f4d7;概念 在 Go 语言中&#xff0c;panic 是一种用于处理异常情况的机制。它允许程序在遇到…

【Windows erver】配置高性能电源管理

操作场景 在 Windows Server 操作系统上&#xff0c;需要配置高性能电源管理&#xff0c;才能支持实例软关机&#xff0c;否则云服务器控制台只能通过硬关机的方式关闭实例。本文档以 Windows Server 2012 操作系统为例&#xff0c;介绍配置电源管理的方法。 操作说明 修改电…

十大内衣洗衣机排名:2024十大实力强大内衣洗衣机推荐

现在洗衣机已经是现代家庭的必备家电&#xff0c;它给我们带来了更加方便舒适的生活。但即使是有了洗衣机大家还是不会将所有的衣物都丢进大型洗衣机洗。尤其是内衣裤、袜子&#xff0c;很多人都是选择手洗的&#xff0c;觉得这样的清洁方式才能清洗干净&#xff0c;但其实事实…

esayExcel根据模板导出包含图片

1、效果 2、模板 3、工具类代码 /*** 根据模板填充* param response* param templateStream 模板文件流* param map 模板文件所需要的参数* param list list循环模板参数* throws IOException*/public static void templateFilling(HttpServletRequest servletRequest,HttpServ…

【Linux系统编程】第四十五弹---线程互斥:从问题到解决,深入探索互斥量的原理与实现

✨个人主页&#xff1a; 熬夜学编程的小林 &#x1f497;系列专栏&#xff1a; 【C语言详解】 【数据结构详解】【C详解】【Linux系统编程】 目录 1、线程互斥 1.1、见一见多线程访问问题 1.2、解决多线程访问问题 1.2.1、互斥量的接口 1.2.2、互斥量接口的使用 1.2.3、…

【贪心算法】贪心算法三

贪心算法三 1.买卖股票的最佳时机2.买卖股票的最佳时机 II3.K 次取反后最大化的数组和4.按身高排序5.优势洗牌&#xff08;田忌赛马&#xff09; 点赞&#x1f44d;&#x1f44d;收藏&#x1f31f;&#x1f31f;关注&#x1f496;&#x1f496; 你的支持是对我最大的鼓励&#…

认知战认知作战:雍正设立军机处的认知战策略分析

认知战认知作战&#xff1a;雍正设立军机处的认知战策略分析 认知战认知作战&#xff1a;雍正设立军机处的认知战策略分析 认知战认知作战&#xff1a;雍正设立军机处的认知战策略分析 关键词&#xff1a;认知作战,新质生产力,人类命运共同体,认知战,认知域,认知战研究中心,认…

AI - 人工智能;Open WebUI;Lobe Chat;Ollama

AI - 人工智能&#xff1b;Ollama大模型工具&#xff1b;Java之SpringAI&#xff08;三&#xff09; 鉴于使用Ollama的命令行交互不是很方便&#xff0c;所以我们需要另一个开源的WebUI&#xff0c;搭建一个能通过浏览器访问的界面&#xff1b;Ollama的Web & Desktop非常多…

特斯拉车速转向电量充电油门刹车档位车门座椅调节灯光信号采集

特斯拉CAN信号采集方案主要包括硬件连接、数据采集与配置、数据解析与可视化等步骤。速锐得主要采集和测试关于特斯拉车速转向电量充电油门刹车档位车门座椅调节灯光信号。 我们拆开特斯拉网关部分用于CAN总线的连接&#xff0c;将CANH和CANL接入到网关对应的CAN针脚&#xff0…

【LLM Agents体验 3】利用Open-WebUI+Ollama本地部署Qwen2.5:7B大模型的安装指南

Open WebUI是一种基于 Web 的用户界面&#xff0c;用于管理和操作各种本地和云端的人工智能模型。它提供了一个直观的图形化界面&#xff0c;使用户可以方便地加载、配置、运行和监控各种 AI 模型&#xff0c;而无需编写代码或使用命令行界面。 Open-WebUI 是一款功能强大且易于…

3.2 Fiddler基础测试

1 请求响应报文 1.1 请求部分 Headers&#xff1a;显示请求的头信息&#xff0c;重点关注请求类型。textView & SyntaxView&#xff1a;分别以纯文本和语法高亮的方式显示请求参数。WebForms&#xff1a;显示请求的 GET 参数和 POST body 内容。HexView&#xff1a;以十六…

《TCP/IP网络编程》学习笔记 | Chapter 9:套接字的多种可选项

《TCP/IP网络编程》学习笔记 | Chapter 9&#xff1a;套接字的多种可选项 《TCP/IP网络编程》学习笔记 | Chapter 9&#xff1a;套接字的多种可选项套接字可选项和 I/O 缓冲大小套接字多种可选项getsockopt & setsockoptSO_SNDBUF & SO_RCVBUF SO_REUSEADDR发生地址绑定…

ISAAC SIM踩坑记录--ROS2相机影像发布

其实这个例子官方和大佬NVIDIA Omniverse和Isaac Sim笔记5&#xff1a;Isaac Sim的ROS接口与相机影像、位姿真值发布/保存都已经有详细介绍了&#xff0c;但是都是基于ROS的&#xff0c;现在最新的已经是ROS2&#xff0c;这里把不同的地方简单记录一下。 搭建一个简单的场景&a…

【C++】模板(一):函数模板

大家好&#xff0c;我是苏貝&#xff0c;本篇博客带大家了解C的函数模板&#xff0c;如果你觉得我写的还不错的话&#xff0c;可以给我一个赞&#x1f44d;吗&#xff0c;感谢❤️ 目录 1&#xff0e;模板2. 函数模板1 概念2 函数模板的实例化(A) 隐式实例化&#xff1a;让编译…