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

Linux:创建进程 -- fork,到底是什么?

 相信大家在初学进程时,对fork函数创建进程一定会有很多的困惑,比如:

  • 1.fork做了什么事情?? 
  • 2.为什么fork函数会有两个返回值?
  • 3.为什么fork的两个返回值,会给父进程谅回子进程pid,给子进程返回0?
  • 4.fork之后:父子进程谁先运行??
  • 5.如何理解同一个变量,会有不同的值??

本篇文章将来仔细回答一下这些问题。

目录

1.如何查看进程

2. 通过系统调用创建进程-fork

2.1 初识fork

2.2 fork原理


1.如何查看进程

1.1 进程的信息可以通过 /proc 系统文件夹查看

通过ls指令来查看所有的进程,proc是动态目录结构,用来存放所有的进程,目录的名称就是用进程的id命名的。

1.2 进程信息同样可以使用ps(process status)工具来获取

  • 进程id(PID)通过getpid 系统调用获得
  • 父进程id(PPID)通过getppid 系统调用获得
   #include<stdio.h>#include<sys/types.h>#include<unistd.h>int main(){while(1){printf("I am a process! myid:%d parentid:%d\n",getpid(),getppid())    ;sleep(1);}return 0;}

 我们可以使用shell再开一个窗口登录一次进行查看。

"aux" 是 "ps" 命令的选项之一,表示显示所有用户的所有进程,通过查询,可以看到你自己 ./ 启动的进程,最后一个进程是当前的grep的查找进程。

关于当前工作目录

我们在C语言学习文件操作是会提到当前目录,我们以 "w" 方式读取文件时,如果文件不存在,那么文件会在当前工作目录cwd下创建。那么一个进程是如何找到当前目录的呢?

我们让下面代码运行起来

  1 #include<stdio.h>2 #include<sys/types.h>3 #include<unistd.h>4 int main()5 {6     //更改当前工作目录7     chdir("./wdz");//没有这个目录不会更改,我这里是创建好了这个目录                                                       8 9     // cwd/hello.txt  10     FILE* file = fopen("hello.txt","w");//文件不存在会在当前工作目录下创建11     if(file==NULL)12     {13         return 1;14     }15     fclose(file);16 17 18     while(1)19     {20         printf("I am a process! myid:%d parentid:%d\n",getpid(),getppid());21         sleep(1);22     }23     return 0;24 }

  这里通过修改当前目录已经对将文件创建在更改的目录下:

  可以发现:

  • 默认情况下,进程所处的目录就是当前工作目录 
  • 一个进程可以找到自己的可执行程序
  • 每一个进程都有自己的工作目录

2. 通过系统调用创建进程-fork

2.1 初识fork

首先使用fork创建一个进程 

    #include<stdio.h>#include<unistd.h>#include<sys/types.h>int main(){printf("我是一个父进程我的pid:%d\n",getpid());//创建一个子进程! pid_t id = fork();//fork之前只有父进程会执行fork之前的代码,fork之后父子进程都要执行后面的代码while(1){printf("我是一个进程,pid:%d,ppid%d,fork return:%d\n",getpid(),getppid(),id);//这个printf函数在代码这里只调用一次,但在运行时调用了两次sleep(1);//for test}return 0;}

 运行结果:

看到这里大家的疑惑就出来了

目前可以发现:只有父进程执行fork之前的代码,fork之后,父子进程都要执行后续的代码!

一个函数竟然会有两个返回值???fork成功的时候,会有两个不同的返回值,给子进程返回0;
给父进程返回子进程的pid

fork代码的一般写法:

1.我们为什么要创建子进程?

        我们想让子进程协作父进程完成一些工作,这些工作是单进程解决不了的

2.我们创建子进程是为了让子进程和父进程做一样的事情吗??

        我们创建子进程,就是为了让子进程和父进程做不一样的事情,执行不一样的代码

3. 应该如何保证父子进程做不一样的事情呢?

        可以通过判断fork的返回值,判断谁是父,谁是子,然后让他们执行不同的代码片段!!

使用 if 对父子进程分流:

#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>int main()
{printf("我是一个父进程我的pid:%d\n",getpid());//创建一个子进程! //bash也是用C语言写的,命令行启动的进程,都是bash的子进程,所以bash源代码中创建子进程也是用的forkpid_t id = fork();  //fork()之后,用if进行分流    if(id<0) return 1; //进程创建失败                                                                                                          else if(id == 0)      {                  //子进程       while(1)       {              printf("我是子进程,pid:%d,ppid%d,ret:%d,正在执行下载\n",getpid(),getppid(),id); sleep(1);//for test      }              }                  else               {                  //父进程       while(1)       {              printf("我是父进程,pid:%d,ppid%d,ret:%d,正在执行播放任务\n",getpid(),getppid(),id);   sleep(1);//for test    }}return 0;
}

执行结果

可以发现通过 if 对fork函数返回值进行判断,实现了父子进程可以执行不同的任务。

2.2 fork原理

对于上面的现象,我们来解答一下疑惑

  • 1.fork做了什么事情?? 
  • 2.为什么fork函数会有两个返回值?
  • 3.为什么fork的两个返回值,会给父进程谅回子进程pid,给子进程返回0?
  • 4.fork之后:父子进程谁先运行??
  • 5.如何理解同一个变量,会有不同的值??

1. fork做了什么事情?? 

       用于创建一个进程,在内核中操作系统重新为其申请了一个PCB,并使用父进程的PCB进行初始化,且子进程与父进程同时指向相同的代码。所以fork之前的代码子进程也是可以看到的。

那为什么子进程不从头开始执行呢?

        因为有程序计数器pc,会使代码一句一句执行,子进程在创建时和继承父进程的pc。所以说也会继续向下执行。


2.为什么fork函数会有两个返回值? 

        首先fork是一个函数,如果一个函数return时,说明一个函数的核心工作已经做完。我们知道fork之后代码会共享,所以是fork函数做完核心工作后就会共享,return也会父子进程共享,所以会有两个返回值。


3.为什么fork的两个返回值,会给父进程谅回子进程pid,给子进程返回0?

        因为一个父进程可以有多个子进程,父进程信息中只有pid 和 ppid,为了唯一确定子进程,所以返回子进程的pid,而子进程中由于有父进程ppid,所以返回0可以用来判断。


4.fork之后:父子进程谁先运行??

        不确定。创建完成子进程,只是一个开始。创建完成子进程之后,系统的其他进程,父进程,和子进程,接下来要被调度执行的,当父子进程的PCB都被创建并在运行队列中排队的时候,哪一个进程的PCB先被选择调度,那个进程就先运行,由操作系统自主决定!!由各自PCB中的调度信息(时间片,优先级等)+调度器算法共同决定。


 5.如何理解同一个变量,会有不同的值??

        进程的独立性,首先是表现在有各自的PCB,进行之间不会互相影响!代码本身是只读的,不会影响!但是数据父子是会修改的,所以代码共享,但是数据各个进程必须想办法各自私有一份!!

这个怎么做到的?通过写时拷贝。这样做的好处就是不用将所有的数据都进行拷贝,当数据需要修改时才做拷贝,可以提高效率。

本篇结束!

相关文章:

Linux:创建进程 -- fork,到底是什么?

相信大家在初学进程时&#xff0c;对fork函数创建进程一定会有很多的困惑&#xff0c;比如&#xff1a; 1.fork做了什么事情?? 2.为什么fork函数会有两个返回值?3.为什么fork的两个返回值&#xff0c;会给父进程谅回子进程pid&#xff0c;给子进程返回0?4.fork之后:父子进…...

基于SpringBoot+vue的token验证

后端&#xff1a; 1&#xff0c;写一个验证token的拦截器 import com.fasterxml.jackson.databind.ObjectMapper; import com.ffyc.news.model.CommonData; import org.springframework.web.servlet.HandlerInterceptor;import javax.servlet.http.HttpServletRequest; impor…...

Clickhouse设置多磁盘存储策略

设置多磁盘存储 clickhouse安装完成以后&#xff0c;配置了一个默认的存储空间&#xff0c; 这个只能配置一个目录&#xff0c;如果要使用多个磁盘目录&#xff0c;则需要配置磁盘组策略 查看当前的存储策略 select name, path, formatReadableSize(free_space) as free, fo…...

Python开发运维:Django 4.2.7 使用Celery 5.3.5 完成异步和定时任务

目录 一、实验 1.Django使用Celery完成异步和定时任务 二、问题 1. 如何查看Django版本 一、实验 1.Django使用Celery完成异步和定时任务 (1)安装Django (2)新建Django项目 (3)初始框架 (4)urls.py引用视图views from django.contrib import admin from django.urls imp…...

媒体增加日活量的有效策略

随着数字媒体的蓬勃发展&#xff0c;提高日活量成为媒体平台追求的重要目标之一。日活量的增加不仅意味着更广泛的影响力&#xff0c;还能为媒体平台带来更多的商业机会。以下是一些有效的策略&#xff0c;可帮助媒体提高日活量&#xff1a; admaoyan猫眼聚合 内容优质化&#…...

es6新特性总结

1、支持了let和const&#xff0c;为了防止var声明变量带来的变量提升 &#xff08;1&#xff09;、存在块级作用域不存在变量提升&#xff08;考虑暂时性死区&#xff09; &#xff08;2&#xff09;、不允许重复声明&#xff08;包括普通变量和函数参数&#xff09;变量提升…...

Spring Boot + hutool 创建海报图片

Spring Boot hutool 创建海报图片 /*** 分享,生成图片* param id* return*/GetMapping("/getShareImg")public void getShareImg(String id,HttpServletResponse response) throws IOException {CouponConsignSaleClassify byId couponConsignSaleClassifyService…...

0002Java程序设计-springboot在线考试系统小程序

文章目录 **摘 要****目录**系统实现开发环境 编程技术交流、源码分享、模板分享、网课分享 企鹅&#x1f427;裙&#xff1a;776871563 摘 要 本毕业设计的内容是设计并且实现一个基于springboot的在线考试系统小程序。它是在Windows下&#xff0c;以MYSQL为数据库开发平台&…...

Linux(Centos)上使用crontab实现定时任务(定时执行脚本)

场景 Windows中通过bat定时执行命令和mysqldump实现数据库备份&#xff1a; Windows中通过bat定时执行命令和mysqldump实现数据库备份_mysqldump bat-CSDN博客 上面讲windows中使用bat实现定时任务的方式&#xff0c;如果是在linux上可以通过crontab实现。 cron是服务名称。…...

【Leetcode合集】20. 有效的括号

20. 有效的括号 20. 有效的括号 代码仓库地址&#xff1a; https://github.com/slience-me/Leetcode 个人博客 &#xff1a;https://slienceme.xyz 给定一个只包括 (&#xff0c;)&#xff0c;{&#xff0c;}&#xff0c;[&#xff0c;] 的字符串 s &#xff0c;判断字符串…...

OpenGL 绘制线(Qt)

文章目录 一、简介二、实现代码三、实现效果参考资料一、简介 这里同样对OpenGL中的绘制线操作进行封装,便于后续的操作,很多形状也都是基于线来生成的,如圆形等。 二、实现代码 LineDrawable.h #ifndef LINE_DRAWABLE_H #define LINE_DRAWABLE_H#include...

Java | 多线程并发编程CountDownLatch实践

关注&#xff1a;CodingTechWork 引言 在一次数据割接需求中&#xff0c;数据需要通过编程的方式进行转移割接到新平台&#xff0c;此时若串行化方式&#xff0c;无疑会拉锯此次战斗&#xff0c;所以首当其冲要使用并发编程来降低割接时长。  本次主要考虑使用CountDownLatc…...

分布式定时任务系列6:XXL-job触发日志过大引发的CPU告警

传送门 分布式定时任务系列1&#xff1a;XXL-job安装 分布式定时任务系列2&#xff1a;XXL-job使用 分布式定时任务系列3&#xff1a;任务执行引擎设计 分布式定时任务系列4&#xff1a;任务执行引擎设计续 分布式定时任务系列5&#xff1a;XXL-job中blockingQueue的应用 …...

Spark RDD、DataFrame和Dataset的区别和联系

一、三种数据介绍 是Spark中的三种不同的数据结构&#xff0c;它们都可以用于分布式数据处理&#xff0c;但是它们的实现方式和使用方法略有不同。 RDD&#xff08;弹性分布式数据集&#xff09; RDD是Spark最初的核心数据结构&#xff0c;它是一个分布式的、只读的、可容错的…...

代码随想录算法训练营第四十五天|139.单词拆分、背包问题总结

LeetCode 139. 单词拆分 题目链接&#xff1a;139. 单词拆分 - 力扣&#xff08;LeetCode&#xff09; 这道题使用完全背包来实现&#xff0c;我们首先考虑字符串是否可以由字符串列表组成&#xff0c;因此dp数组大小为n 1 &#xff0c;其意义是&#xff0c;在n个位置时是否能…...

深度学习卫星遥感图像检测与识别 -opencv python 目标检测 计算机竞赛

文章目录 0 前言1 课题背景2 实现效果3 Yolov5算法4 数据处理和训练5 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; **深度学习卫星遥感图像检测与识别 ** 该项目较为新颖&#xff0c;适合作为竞赛课题方向&#xff0c;学长非常推荐…...

wxWidgets 3.2.4发布 —— 发布于2023年11月11日

稳定的3.2系列中的另一个版本现在可以在GitHub上获得。您可以在那里找到包含库源代码和文档的归档文件&#xff0c;以及所选Windows编译器&#xff08;如Microsoft Visual C、MinGW-w64和TDM-GCC&#xff09;的二进制文件。您还可以阅读此版本的更新文档&#xff0c;特别是&…...

PyQt6运行QTDesigner生成的ui文件程序

2024版 PyQt6 Python桌面开发 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili2024版 PyQt6 Python桌面开发 视频教程(无废话版) 玩命更新中~共计18条视频&#xff0c;包括&#xff1a;2024版 PyQt6 Python桌面开发 视频教程(无废话版) 玩命更新中~、第2讲 PyQt6库和工具库Q…...

基于mediapipe的人手21点姿态检测模型—CPU上检测速度惊人

前期的文章,我们介绍了MediaPipe对象检测与对象分类任务,也分享了MediaPipe的人手手势识别。在进行人手手势识别前,MediaPipe首先需要进行人手的检测与人手坐标点的检测,经过以上的检测后,才能把人手的坐标点与手势结合起来,进行相关的手势识别。 MediaPipe人手坐标点检测…...

系统架构设计: 21 论敏捷软件开发方法及其应用

论敏捷软件开发方法及其应用 请围绕“敏捷软件开发方法及其应用”论题,依次从以下三个方面进行论述。 ①简述你所参与开发的运用了敏捷技术的项目,以及你所担任的工作; ②分析并讨论敏捷<...

告别HTTP请求焦虑:用CSS Sprites(精灵图)优化你的Vue/React项目图片加载

告别HTTP请求焦虑&#xff1a;用CSS Sprites&#xff08;精灵图&#xff09;优化你的Vue/React项目图片加载 在当今快节奏的Web开发领域&#xff0c;性能优化始终是开发者关注的焦点。当我们构建复杂的单页应用&#xff08;SPA&#xff09;时&#xff0c;图片资源的管理往往成为…...

如何处理SQL存储过程编码格式_检查数据库默认排序规则

SQL Server存储过程中文乱码主因是排序规则不匹配而非字符集问题&#xff0c;需逐层检查数据库、表列、字符串字面量&#xff08;须加N前缀&#xff09;、动态SQL及客户端驱动是否统一支持Unicode或UTF-8排序规则。SQL Server 存储过程中中文乱码&#xff0c;大概率是排序规则不…...

RPG Maker MV/MZ资源解密终极指南:三步解锁你的游戏素材宝库

RPG Maker MV/MZ资源解密终极指南&#xff1a;三步解锁你的游戏素材宝库 【免费下载链接】RPG-Maker-MV-Decrypter You can decrypt RPG-Maker-MV Resource Files with this project ~ If you dont wanna download it, you can use the Script on my HP: 项目地址: https://g…...

KUKA C2通讯故障排查实录:从‘扫描器出错’到电源电压,我踩过的那些坑

KUKA C2通讯故障排查实战手册&#xff1a;从电源电压到数据一致性的深度解析 当KUKA机器人投入产线运行后&#xff0c;最令人头疼的莫过于那些神出鬼没的通讯故障。作为一名经历过无数次深夜抢修的工程师&#xff0c;我深知一个看似简单的"扫描器出错"背后可能隐藏着…...

从YouTube视频到16个关键点:手把手教你用Python解析MPII人体姿态数据集(附完整代码)

从YouTube视频到16个关键点&#xff1a;Python实战MPII人体姿态数据集解析与可视化 当我们需要训练一个能够理解人体姿态的AI模型时&#xff0c;高质量的数据集是成功的关键。MPII Human Pose Database作为计算机视觉领域的标杆数据集&#xff0c;包含了从YouTube视频中提取的2…...

GenUI:从“文本对话”到“可操作界面”的范式转移

写在前面假如我问你&#xff1a;“帮我推荐几双500元以下的跑鞋。”传统AI会回复一段文字&#xff1a;“推荐李宁超轻系列&#xff0c;价格XXX&#xff1b;安踏氢跑系列……”你读完&#xff0c;再去电商App搜索、筛选、下单。整个过程在“读—搜—筛”之间反复跳转。但如果AI直…...

别再只看信号格了!5G网速上不去?手把手教你用RSRP、SNR、BLER看懂手机里的真实信道质量

手机信号满格却网速慢&#xff1f;5G时代必懂的RSRP、SNR、BLER诊断指南 你是否遇到过这样的情况&#xff1a;手机信号显示满格&#xff0c;但刷视频却频繁缓冲&#xff0c;下载文件速度慢如蜗牛&#xff1f;这种"信号假象"在5G时代尤为常见。本文将带你揭开手机信号…...

Jetson Nano上MediaPipe GPU加速实战:从编译到部署,让你的AI应用帧率翻倍

Jetson Nano上MediaPipe GPU加速实战&#xff1a;从编译到部署&#xff0c;让你的AI应用帧率翻倍 在嵌入式AI领域&#xff0c;Jetson Nano凭借其出色的GPU性能成为众多开发者的首选平台。然而&#xff0c;当我们将Google的MediaPipe框架部署到这块开发板上时&#xff0c;默认的…...

别再死磕COE文件了!Vivado里用$readmemb/h给RAM上电初始化的正确姿势(附避坑指南)

Vivado中RAM初始化的终极方案&#xff1a;告别COE文件&#xff0c;掌握$readmemb/h的正确用法 在FPGA开发中&#xff0c;RAM初始化是个看似简单却暗藏玄机的环节。许多开发者都曾陷入这样的困境&#xff1a;按照官方文档和主流教程使用COE文件初始化IP核&#xff0c;结果上电后…...

Parsec VDD:Windows虚拟显示器终极解决方案,免费扩展你的数字工作空间

Parsec VDD&#xff1a;Windows虚拟显示器终极解决方案&#xff0c;免费扩展你的数字工作空间 【免费下载链接】parsec-vdd ✨ Perfect virtual display for game streaming 项目地址: https://gitcode.com/gh_mirrors/pa/parsec-vdd 在当今多任务处理日益普及的数字时代…...