当前位置: 首页 > news >正文

操作系统-实验-进程

怎样创建一个子进程

首先配置号c语言的环境 gcc编译

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>int main()
{//pid_t是数据类型,实际上是一个整型,通过typedef重新定义了一个名字,用于存储进程idpid_t pid,cid;//getpid()函数返回当前进程的id号printf("Before fork Process id :%d\n", getpid());/*fork()函数用于创建一个新的进程,该进程为当前进程的子进程,创建的方法是:将当前进程的内存内容完整拷贝一份到内存的另一个区域,两个进程为父子关系,他们会同时(并发)执行fork()语句后面的所有语句。fork()的返回值:如果成功创建子进程,对于父子进程fork会返回不同的值,对于父进程它的返回值是子进程的进程id值,对于子进程它的返回值是0.如果创建失败,返回值为-1.*/cid = fork();printf("After fork, Process id :%d\n", getpid());pause();return 0;
}

在这里插入图片描述

gcc helloProcess.c -o helloProcess

执行下

./helloProcess 

在这里插入图片描述
可以看到有三行输出
前两行创建子进程之前和创建子进程之后都为91476,这个91476为父进程的pid,在创建了子进程后,子进程只打印了after fork日志

印证下父子进程的关系
在这里插入图片描述
可以看到倒数后两行,81479的ppid即父进程为91476

在这里插入图片描述
其中有个关键函数fork函数,这个函数的作用为创建子进程
子进程将父进程完全复制一份内存空间变成子进程
在执行了fork之后会并发执行fork之后的所有代码,注意并发执行为交替执行,同一时刻只会有一个程序运行,原因以及父子进程执行时机区别如下:

  • fork 创建子进程时,系统会为子进程分配独立的地址空间,但初始时父子进程共享相同的代码段(即程序计数器指向同一位置)。当子进程开始执行时,其程序计数器会从fork()调用点开始继续执行后续代码,而父进程则从fork()返回后继续执行后续代码
  • 地址空间隔离‌
    – fork()调用后,子进程获得父进程的内存映像副本(包括代码和数据),但操作系统通常采用‌写时复制‌(copy-on-write)机制优化资源使用,即初始共享地址空间仅在写入时才分配给子进程独立空间。 ‌
  • 程序计数器初始化‌
    – 子进程的初始程序计数器值与父进程相同,均指向fork()调用点。随后子进程通过程序计数器自动跳转到fork()之后的代码执行。 ‌
  • 执行机制差异‌
    – 父进程在fork()返回后继续执行后续代码,而子进程则从fork()返回点开始执行后续代码。这种机制确保父子进程按预期逻辑分离执行

可以看到刚才的程序fork之后先执行了父进程的打印日志,再执行的子进程的打印日志,那怎样让子进程先运行,父进程后运行呢

首先来看看怎样区分父子进程

区分父子进程

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>int main()
{//pid_t是数据类型,实际上是一个整型,通过typedef重新定义了一个名字,用于存储进程idpid_t pid,cid;//getpid()函数返回当前进程的id号printf("Before fork Process id :%d\n", getpid());/*fork()函数用于创建一个新的进程,该进程为当前进程的子进程,创建的方法是:将当前进程的内存内容完整拷贝一份到内存的另一个区域,两个进程为父子关系,他们会同时(并发)执行fork()语句后面的所有语句。fork()的返回值:如果成功创建子进程,对于父子进程fork会返回不同的值,对于父进程它的返回值是子进程的进程id值,对于子进程它的返回值是0.如果创建失败,返回值为-1.*/cid = fork();printf("After fork, Process id :%d\n", cid);pause();return 0;
}

在这里插入图片描述

注意这里的after 打印日志 改成了cid
cid即fork()的返回值:

  • 如果成功创建子进程,对于父子进程fork会返回不同的值,对于父进程它的返回值是子进程的进程id值,对于子进程它的返回值是0.
  • 如果创建失败,返回值为-1.

判断父子进程打印日志

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>int main()
{//pid_t是数据类型,实际上是一个整型,通过typedef重新定义了一个名字,用于存储进程idpid_t pid,cid;//getpid()函数返回当前进程的id号printf("Before fork Process id :%d\n", getpid());/*fork()函数用于创建一个新的进程,该进程为当前进程的子进程,创建的方法是:将当前进程的内存内容完整拷贝一份到内存的另一个区域,两个进程为父子关系,他们会同时(并发)执行fork()语句后面的所有语句。fork()的返回值:如果成功创建子进程,对于父子进程fork会返回不同的值,对于父进程它的返回值是子进程的进程id值,对于子进程它的返回值是0.如果创建失败,返回值为-1.*/cid = fork();if (cid ==0){ //子进程printf("Child Process id :%d\n",getpid());}else{ //父进程printf("parent Process id :%d\n",getpid());}pause();return 0;
}

在这里插入图片描述

在父子进程加上for循环

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>int main()
{pid_t cid;printf("Before fork process id :%d\n", getpid());cid = fork();if(cid == 0){ //该分支是子进程执行的代码printf("Child process id (my parent pid is %d):%d\n", getppid(),getpid());for(int i=0; i<3 ; i++)printf("hello\n");}else{ //该分支是父进程执行的代码printf("Parent process id :%d\n", getpid());for(int i=0; i<3 ; i++)printf("world\n");}return 0;
}

在这里插入图片描述
可以看到先执行副进程的3次for循环,再执行子进程的3次循环

父子进程执行顺序

从上述实验看出父子进程好像执行有顺序,但时机父子进程为并发执行的,但为啥看起来像是串行执行的呢

这个是由于执行的循环此时太少 CPU一次执行得太快看起来没有并发交替执行
把循环此时增加再看看

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>int main()
{pid_t cid;printf("Before fork process id :%d\n", getpid());cid = fork();if(cid == 0){ //该分支是子进程执行的代码printf("Child process id (my parent pid is %d):%d\n", getppid(),getpid());for(int i=0; i<300 ; i++)printf("hello\n");}else{ //该分支是父进程执行的代码printf("Parent process id :%d\n", getpid());for(int i=0; i<300 ; i++)printf("world\n");}return 0;
}

在这里插入图片描述

进程之间的变量共享

假设在父子进程执行之前定义了变量value,在两个进程的变量会怎样变化呢

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>int main()
{pid_t cid;int value = 100;cid = fork();if(cid == 0){ //该分支是子进程执行的代码for(int i=0; i<3 ; i++)printf("In child: value=%d\n",value--);}else{ //该分支是父进程执行的代码for(int i=0; i<3 ; i++)printf("In parent: value=%d\n", value++);}return 0;
}

在这里插入图片描述
可以看到父进程执行了3次加法,子进程重新从100开始做减法了,说明进程之间的内存不共享,fork会复制一份新的,包括其中的变量

孤儿进程

wait (NULL) 等待子进程结束再执行 当子进程执行return 父进程再会进程ready状态
不使用的时候子进程执行完成不会等待父进程执行完成会变成孤儿进程

在这里插入图片描述
sleep函数,在子进程加上 等待3s会进入ready 父进程有wait函数会等待子进程等待时间再结束 但父进程不加上wait 则子进程仍然会变成孤儿进程
在这里插入图片描述

参考
B站操作系统

http://www.xdnf.cn/news/1260811.html

相关文章:

  • 以下是使用这款ePub编辑器将指定章节转换为TXT文本文档的操作方法
  • (已解决)IDEA突然无法使用Git功能
  • 手机拍照识别中模糊场景准确率↑37%:陌讯动态适配算法实战解析
  • hyper-v虚拟机启动失败:Virtual Pci Express Port无法打开电源,因为发生错误,找不到即插即用设备
  • SQL Server 2019搭建AlwaysOn高可用集群
  • Money Sums
  • 【优选算法】BFS解决拓扑排序
  • UE4/UE5 Android 超大(视频)文件打包/防拷贝方案
  • Linux 内存管理之page folios
  • node.js 学习笔记2 进程/线程、fs
  • (已解决)Mac 终端上配置代理
  • 人工智能与智能家居:家居生活的变革
  • GO的启动流程(GMP模型/内存)
  • Go语言实战案例:用net/http构建一个RESTful API
  • 关于csdn导入和导出
  • 服务器硬件电路设计之I2C问答(一):为什么I2C总线要加上拉电阻?
  • Vue框架进阶
  • DM8数据库服务正常,但是登录报错 [-70019]:没有匹配的可登录服务器
  • 如何解决pip安装报错ModuleNotFoundError: No module named ‘huggingface_hub’问题
  • proteus实现简易DS18B20温度计(stm32)
  • 《论文阅读》传统CoT方法和提出的CoT Prompting的区分
  • [链表]142. 环形链表 II
  • C# GUI程序中的异步操作:解决界面卡顿的关键技术
  • OpenCV 3 终极指南:创建炫酷自定义窗口与图像显示的艺术
  • ctfshow_萌新web9-web13-----rce
  • 自动驾驶--车辆动力学模型
  • linux安装mysql8.0,二进制码安装
  • SpringCloud(4)-多机部署,负载均衡-LoadBalance
  • 数据持久化 —— `chrome.storage` 的记忆魔法
  • Java学习进阶--集合体系结构