当前位置: 首页 > 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.dtcms.com/a/321195.html

相关文章:

  • 机器学习之支持向量机(原理)
  • svm的一些应用
  • 怎么查看Linux I2C总线挂载了那些设备?
  • springboot整合rabbitMQ的示例
  • Elasticsearch:在向量搜索中使用 Direct IO
  • 解码华为云安全“铁三角”:用“分层防御”化解安全挑战
  • 微软披露Exchange Server漏洞:攻击者可静默获取混合部署环境云访问权限
  • 企业AI的双层技术栈架构:融合社区创新与企业级管控的设计蓝图
  • Git 使用场景笔记
  • DuoPlus支持导入文件批量配置云手机参数,还优化了批量操作和搜索功能!
  • 数据结构--哈希表
  • QAGenerationChain从知识库生成大模型应用测试的问题对
  • LeetCode算法日记 - Day 5: 长度最小的子数组、无重复字符的最长子串
  • 【uni-app】解决在 h5 环境下会出现双标题问题
  • 内核的调试和优化
  • Netty-Rest搭建笔记
  • 微算法科技(NASDAQ:MLGO)使用循环QSC和QKD的量子区块链架构,提高交易安全性和透明度
  • 降低程序运行时CPU和GPU峰值占用的技术方案
  • 基于深度学习的鸟类检测识别系统(yolo11、yolov8、yolov5+UI界面+Python项目源码+模型+标注好的数据集)
  • ROHM推出适用于Zone-ECU的高性能智能高边开关!
  • 【unitrix数间混合计算】2.3 标准化处理系统(src/number/normalize/mod.rs)
  • Alkimi 与 Sui 合作,修复「破碎」的广告生态
  • HarmonyOS多设备资源文件管理以及resources资源引用方式
  • 交换机100G模块远距离连接踩坑记录
  • 强制用户更改WordPress密码的重要性及实现方法
  • Pinterest视觉营销自动化:亚矩阵云手机实例与多分辨率适配技术
  • 在 Elasticsearch/Kibana (ELK Stack) 中搜索包含竖线 (|)​​ 这类特殊字符的日志消息 (msg 字段) ​确实需要转义
  • proteus实现简易DS18B20温度计(stm32)
  • python学智能算法(三十五)|SVM-软边界拉格朗日方程乘子非负性理解
  • 阿里云服务linux安装单机版