当前位置: 首页 > 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 论敏捷软件开发方法及其应用

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

HTML 语义化

目录 HTML 语义化HTML5 新特性HTML 语义化的好处语义化标签的使用场景最佳实践 HTML 语义化 HTML5 新特性 标准答案&#xff1a; 语义化标签&#xff1a; <header>&#xff1a;页头<nav>&#xff1a;导航<main>&#xff1a;主要内容<article>&#x…...

日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする

日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする 1、前言(1)情况说明(2)工程师的信仰2、知识点(1) にする1,接续:名词+にする2,接续:疑问词+にする3,(A)は(B)にする。(2)復習:(1)复习句子(2)ために & ように(3)そう(4)にする3、…...

生成 Git SSH 证书

&#x1f511; 1. ​​生成 SSH 密钥对​​ 在终端&#xff08;Windows 使用 Git Bash&#xff0c;Mac/Linux 使用 Terminal&#xff09;执行命令&#xff1a; ssh-keygen -t rsa -b 4096 -C "your_emailexample.com" ​​参数说明​​&#xff1a; -t rsa&#x…...

【AI学习】三、AI算法中的向量

在人工智能&#xff08;AI&#xff09;算法中&#xff0c;向量&#xff08;Vector&#xff09;是一种将现实世界中的数据&#xff08;如图像、文本、音频等&#xff09;转化为计算机可处理的数值型特征表示的工具。它是连接人类认知&#xff08;如语义、视觉特征&#xff09;与…...

BCS 2025|百度副总裁陈洋:智能体在安全领域的应用实践

6月5日&#xff0c;2025全球数字经济大会数字安全主论坛暨北京网络安全大会在国家会议中心隆重开幕。百度副总裁陈洋受邀出席&#xff0c;并作《智能体在安全领域的应用实践》主题演讲&#xff0c;分享了在智能体在安全领域的突破性实践。他指出&#xff0c;百度通过将安全能力…...

《基于Apache Flink的流处理》笔记

思维导图 1-3 章 4-7章 8-11 章 参考资料 源码&#xff1a; https://github.com/streaming-with-flink 博客 https://flink.apache.org/bloghttps://www.ververica.com/blog 聚会及会议 https://flink-forward.orghttps://www.meetup.com/topics/apache-flink https://n…...

微信小程序云开发平台MySQL的连接方式

注&#xff1a;微信小程序云开发平台指的是腾讯云开发 先给结论&#xff1a;微信小程序云开发平台的MySQL&#xff0c;无法通过获取数据库连接信息的方式进行连接&#xff0c;连接只能通过云开发的SDK连接&#xff0c;具体要参考官方文档&#xff1a; 为什么&#xff1f; 因为…...

实现弹窗随键盘上移居中

实现弹窗随键盘上移的核心思路 在Android中&#xff0c;可以通过监听键盘的显示和隐藏事件&#xff0c;动态调整弹窗的位置。关键点在于获取键盘高度&#xff0c;并计算剩余屏幕空间以重新定位弹窗。 // 在Activity或Fragment中设置键盘监听 val rootView findViewById<V…...

【JavaWeb】Docker项目部署

引言 之前学习了Linux操作系统的常见命令&#xff0c;在Linux上安装软件&#xff0c;以及如何在Linux上部署一个单体项目&#xff0c;大多数同学都会有相同的感受&#xff0c;那就是麻烦。 核心体现在三点&#xff1a; 命令太多了&#xff0c;记不住 软件安装包名字复杂&…...

以光量子为例,详解量子获取方式

光量子技术获取量子比特可在室温下进行。该方式有望通过与名为硅光子学&#xff08;silicon photonics&#xff09;的光波导&#xff08;optical waveguide&#xff09;芯片制造技术和光纤等光通信技术相结合来实现量子计算机。量子力学中&#xff0c;光既是波又是粒子。光子本…...