【Linux】进程概念与fork初识——if与else竟然能够同时执行?!

这篇具有很好参考价值的文章主要介绍了【Linux】进程概念与fork初识——if与else竟然能够同时执行?!。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

【Linux】进程概念与fork初识——if与else竟然能够同时执行?!

💐专栏导读

🌸作者简介:花想云 ,在读本科生一枚,C/C++领域新星创作者,新星计划导师,阿里云专家博主,CSDN内容合伙人…致力于 C/C++、Linux 学习。

🌸专栏简介:本文收录于 Linux从入门到精通,本专栏主要内容为本专栏主要内容为Linux的系统性学习,专为小白打造的文章专栏。

🌸相关专栏推荐:C语言初阶系列C语言进阶系列C++系列数据结构与算法

💐文章导读

本章我们正式进入进程的学习。本章的主要内容有进程的概念、PCB说明、进程的先描述再组织、如何查看进程、以及学习getpidgetppidfork等系统调用如何使用~

【Linux】进程概念与fork初识——if与else竟然能够同时执行?!

🌷进程是什么

开门见山一句话——

  • 进程=内核关于进程的相关数据结构+当前代码的内容和数据

🍁如何理解?

当我们写好一段代码进行编译、链接等一系列过程之后,生成了可执行程序。此时的可执行程序是一个文件,被存放到硬盘中。当我们运行该可执行程序后,该程序的代码和数据会被预先加载到内存中(至于原因上一章我们已经做了很好的铺垫),同时操作系统会对该进程建模,提取该进程有关的状态信息等所有的属性并将这些信息保存到一个叫PCB的结构体中,并将该PCB的指针保存到某种例如链表一样的数据结构当中,以进行对进程的增删查改一系列操作。

简单归纳,“程序被加载到内存中就成为了进程”这就话并不准确,关键是该进程相关的信息有没有被操作系统所管理。就如同,诺大的校园中,如何证明你是学校的学生呢?你说你能从学校的大门进到学校里来,这显然不能说明你就是这个学校的学生,而是当学校的档案系统里记录了你的信息,才能证明你是这个学校的学生。

所以,以前我们任何将程序启动并运行的行为本质上是操作系统将该程序转化为进程从而完成特定的任务。

上文中还有一个很中还要的点需要我们来理解——PCB是什么?有什么作用?

🌷进程的描述——PCB

操作系统如何管理进程?还记得上一章中最重要的六个字吗?——先描述,再组织PCB就是对进程的一种描述。

  • 进程信息被放在一个叫做进程控制块的数据结构中,可以理解为进程属性的集合
  • 课本上称之为PCB(process control block),Linux操作系统下的PCB是:task_struct

总结为一句话就是——在Linux中描述进程的结构体叫做task_structtask_struct是Linux内核的一种数据结构,它会被装载到RAM(内存)里并且包含着进程的信息

🍁task_struct包含以下内容:

  • 标示符: 描述本进程的唯一标示符,用来区别其他进程;
  • 状态: 任务状态,退出代码,退出信号等;
  • 优先级: 相对于其他进程的优先级;
  • 程序计数器: 程序中即将被执行的下一条指令的地址;
  • 内存指针: 包括程序代码和进程相关数据的指针,还有和其他进程共享的内存块的指针;
  • 上下文数据: 进程执行时处理器的寄存器中的数据[休学例子,要加图CPU,寄存器;
  • I/O状态信息: 包括显示的I/O请求,分配给进程的I/O设备和被进程使用的文件列表;
  • 记账信息: 可能包括处理器时间总和,使用的时钟数总和,时间限制,记账号等;
  • 其他信息

🌷进程的组织

所有的进程都会以task_struct结构体的形式被描述起来。而这些task_struct结构体都会被链接起来,生成一个task_struct类型的链表。操作系统对进程的控制就会转化为对task_struct增删查改

🌷如何查看进程

首先我们写一个简单的程序(命名为myprocess),并运行:

#include<stdio.h>

int main()
{
  while(1)
  {
    printf("我是一个进程\n");
    sleep(1);
  }
  return 0;
}
$ gcc myprocess.c -o myprocess
$ ./myprocess

在分屏的情况下,输入指令查看进程:

ps axj | head -1 && ps axj | grep myprocess | grep -v grep

我们暂且不需要管这条指令的具体指令有什么作用,只需要知道它能显示当前myprocess进程的信息。如图所示:

【Linux】进程概念与fork初识——if与else竟然能够同时执行?!
虽然我们现在可能看不到每个标识符代表什么意思,但是其它先不用管,只需要知道PID是当前进程的ID,就如同我们的学号

🍁第二种方式

还有一种查看进程的方式:

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

让我们再以myprocess为例。

  • 进入/proc目录;
  • ls 查看目录下的文件;

🍁myprocess未运行时

【Linux】进程概念与fork初识——if与else竟然能够同时执行?!
我们观察到有很多数字命名的文件,其实猜测一下就能大致猜出这些数字应该就是每个进程对应的PID。

  • 运行myprocess

🍁myprocess运行时

【Linux】进程概念与fork初识——if与else竟然能够同时执行?!

如图所示,该目录下的确有该进程的相关文件。

🌷如何通过系统调用查看进程PID

除了上述以指令的方式输出PID外,我们还可以用系统调用getpid()获取当前进程的pidgetppid()获取当前进程的父进程的PID

首先通过man手册查询这两个函数如何使用:

$ man getpid

【Linux】进程概念与fork初识——if与else竟然能够同时执行?!
注意,返回值类型未pid_t其实就是size_t。通过一下代码进行测试:

#include<stdio.h>
#include<sys/types.h>

int main()
{
  while(1)
  {
    printf("我是一个进程,我的PID是:%d,我的父进程是:%d\n",getpid(),getppid());
    sleep(1);
  }
  return 0;
}

运行结果为:
【Linux】进程概念与fork初识——if与else竟然能够同时执行?!
当我们尝试不断地启动程序和结束程序:

【Linux】进程概念与fork初识——if与else竟然能够同时执行?!
我们可以发现一个规律:

  • 每次启动时,该进程的PID都不同,但是PPID好像每次都一样。

那么PID是什么呢?为什么会不变呢?当你在命令行中启动任何一个进程,它的父进程的PID都是它,即这些进程都有一个共同的父进程——bash(命令行解释器)。如图所示:

【Linux】进程概念与fork初识——if与else竟然能够同时执行?!

🌷通过系统调用创建进程

接下来的内容为本章的重点内容——认识fork与如何通过fork创建子进程

🌺认识fork

首先我们通过man手册认识一下fork

$ man fork

【Linux】进程概念与fork初识——if与else竟然能够同时执行?!
【Linux】进程概念与fork初识——if与else竟然能够同时执行?!

简单说明就是**fork用来创建子进程,在父进程中,fork的返回值为子进程的PID;在子进程中返回值为0**。

话不多说,我们来进行测试:

#include<stdio.h>
#include<sys/types.h>

int main()
{
  printf("我是fork调用之前的内容.....\n");
  fork();
  printf("我是fork调用之后的内容.....\n");

  return 0;
}

【Linux】进程概念与fork初识——if与else竟然能够同时执行?!
很显然,这里fork调用之后的内容打印了两遍。原因是当调用fork之后,子进程被创建,父进程与子进程同时在运行,于是父进程打印了一遍fork调用后的内容,子进程也打印了一遍fork调用后的内容。

如何证明呢?修改代码,在打印内容的同时打印父子进程各自的PIDPPID

#include<stdio.h>
#include<sys/types.h>

int main()
{
  printf("我是fork调用之前的内容.....我的PID是:%d,我的父进程是:%d\n",getpid(),getppid());
  fork();
  printf("我是fork调用之后的内容.....我的PID是:%d,我的父进程是:%d\n",getpid(),getppid());

  return 0;
}

【Linux】进程概念与fork初识——if与else竟然能够同时执行?!

🌺重点来啦!!!

fork的功能很强大,我们一般需要与if配合使用进行分流。还记得上面提到的fork的返回值吗?子进程返回值为0,父进程返回值为子进程PID,可以此作为分流的依据。例如:

#include<stdio.h>
#include<sys/types.h>

int main()
{
  pid_t ret = fork();

  if(ret==0)
  {
    // 子进程
    while(1)
    {
       printf("我是子进程,我的PID是:%d,我的父进程是:%d\n",getpid(),getppid());
       sleep(1);
    }
  }
  else 
  {
    // 父进程
    while(1)
    {
       printf("我是父进程,我的PID是:%d,我的父进程是:%d\n",getpid(),getppid());
       sleep(1);
    }
  }

  return 0;
}

【Linux】进程概念与fork初识——if与else竟然能够同时执行?!

如图所示,此刻父子进程都在运行。那么问题来了——

  • 请问为什么此时ifelse竟然能够同时执行?也就是fork为什么会有两个返回值
  • 又问为什么此时的ret竟然会同时存在两个不同的值?

以上的问题确实有些颠覆初学者的三观。在本章节我们只能够试着解决第一个问题,至于第二个问题,我们在后续进程地址空间中会解释明白。

首先,我们得清楚一个基本概念:

  • 进程间是互相独立的

例如qq与微信同时运行,两个并无关联,互不影响。

其次我们要明白子进程是如何创建的。

我们知道进程=内核数据结构(PCB)+代码和数据。当子进程创建时,操作系统会为子进程创建一个PCB记录子进程的状态信息等。同时子进程会与父进程共同使用一份代码和数据,若有任意一个执行流(只父子进程)修改数据时,操作系统会为该进程将代码和数据拷贝一份,再进行修改,此动作我们称之为写时拷贝写时拷贝同样为非常重要的知识,但是现在我们只做了解即可。

最后,因为进程具有独立性,同样父子进程也具有独立性,且由于写时拷贝的存在,父进程中调用fork会返回子进程的PID,所以else执行了,这是父进程的行为;子进程中会fork会返回0,所以if执行了,这是子进程的行为。父子进程互不影响。

本章的内容就到这里了。关于fork我们还需要学习很多,本章我们就先简单认识一下即可。

【Linux】进程概念与fork初识——if与else竟然能够同时执行?!

点击下方个人名片,可添加博主的个人QQ,交流会更方便哦~
↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓文章来源地址https://www.toymoban.com/news/detail-427593.html

到了这里,关于【Linux】进程概念与fork初识——if与else竟然能够同时执行?!的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Linux初阶】fork进程创建 & 进程终止 & 进程等待

     🌟hello,各位读者大大们你们好呀🌟 🍭🍭系列专栏:【Linux初阶】 ✒️✒️本篇内容:fork进程创建,理解fork返回值和常规用法,进程终止(退出码、退出场景、退出方法、exit),进程等待(wait、waitpid),阻塞等待和非阻塞等待 🚢🚢作者简介:本科在读,计算机海洋

    2024年02月06日
    浏览(33)
  • Linux中的进程、fork、进程状态、环境变量

            进程信息被放在一个叫做进程控制块的数据结构中,可以理解为进程属性的集合。课本上称之为PCB(process control block),Linux操作系统下的PCB是: task_struct 在Linux中描述进程的结构体叫做task_struct。task_struct是Linux内核的一种数据结构,它会被装载到RAM(内存)里并且包

    2024年02月10日
    浏览(36)
  • Linux------进程的fork()详解

    目录 前言 一、fork()的使用 二、fork()的返回值 我们为什么要创建子进程? 父进程与子进程的分流 三、fork的一些难理解的问题 1.fork干了什么事情? 2.fork为什么会有两个返回值  3.fork的两个返回值,为什么会给父进程返回子进程pid,给子进程返回0? 4.fork之后,父子进程谁先

    2024年01月18日
    浏览(28)
  • Linux:创建进程 -- fork,到底是什么?

     相信大家在初学进程时,对fork函数创建进程一定会有很多的困惑,比如: 1.fork做了什么事情??  2.为什么fork函数会有两个返回值? 3.为什么fork的两个返回值,会给父进程谅回子进程pid,给子进程返回0? 4.fork之后:父子进程谁先运行?? 5.如何理解同一个变量,会有不同的值?? 本

    2024年02月05日
    浏览(29)
  • Linux--进程--vfork与fork区别

    vfork: 所需头文件: #include sys/types.h #include unistd.h pid_t vfork(void); 功能: vfork() 函数和 fork() 函数一样都是在已有的进程中创建一个新的进程,但它们创建的子进程是有区别的。 参数: 无 返回值: 成功:子进程中返回 0,父进程中返回子进程 ID。pid_t,为无符号整型。 失败:

    2024年02月10日
    浏览(28)
  • C 知识积累 替换gets函数 Linux C 语法分析 switch和if else的比较

    gets()用处 gets从标准输入设备读字符串函数,其可以无限读取,不会判断上限,可以包含空格,以回车结束读取。 gets()的危险之处 因为该函数可以无限读取,所以应该确保buffer的空间足够大,以便在执行读操作时不发生溢出。如果溢出,多出来的字符将被写入到堆栈中,这就

    2024年02月16日
    浏览(31)
  • 头歌(Linux之进程管理一):第2关:进程创建操作-fork

    任务描述 在上一关我们学习如何获取进程的 pid 信息,本关我们将介绍如何编程创建一个新的进程。 本关任务:学会使用 C 语言在 Linux 系统中使用 fork 系统调用创建一个新的进程。 相关知识 在 Linux 系统中创建进程有很多函数可以使用,其中包括了系统调用也包括库函数。

    2024年02月06日
    浏览(29)
  • 【Linux】进程与可执行程序的关系&&fork创建子进程&&写实拷贝的理解

            系统会将此时在系统运行的进程的各种属性都以文件的形式给你保存在系统的proc目录下。 运行一个程序的时候,本质就是把磁盘中的程序拷贝到内存中,当一个进程运行起来的时候,它本质已经和磁盘中的可执行程序没有直接关系了。   当前我的myprocess程序正在运

    2024年03月19日
    浏览(31)
  • Linux网络编程:socket & fork()多进程 实现clients/server通信

    UNIX网络编程:socket实现client/server通信 随笔简单介绍了TCP Server服务单客户端的socket通信,但是并未涉及多客户端通信。 对于网络编程肯定涉及到多客户端通信和并发编程 (指在同时有大量的客户链接到同一服务器),故本随笔补充这部分知识。 而且并发并发编程涉及到多进程

    2024年02月05日
    浏览(35)
  • 【自学Java】Java if else-if else语句

    在 Java 语言 中, if 是用于测试某个条件( 布尔型 或逻辑型)的语句是否满足一定的条件,如果满足特定的条件,则会执行 if 后由大括号 {} 括起来的代码块,否则就忽略该代码块继续执行后续的代码。 else if 用于在 if 语句条件不满足的情况下,继续执行 else

    2024年02月06日
    浏览(42)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包