操作系统进程2---进程成员以及fork

news2025/1/16 6:40:49
在上一次我们认识了什么是进程以及进程在操作系统中是如何被管理的。今天我们来认识一下pcb中的成员

Linux中我们可以使用ps命令中的ajx选项来输出当前系统中所有的进程
在这里插入图片描述
而我们就先从pid和ppid来入手。

文章目录

  • 1.进程中的pid和ppid
  • 2.父进程与子进程的简单认识
  • 3.系统调用函数
    • 1). getpid,getppid
    • 2). fork
      • a. fork简单认识
      • b. fork的用法
      • c. fork的原理

1.进程中的pid和ppid

进程pcb中有两个成员,一个是pid,一个是ppid,pid是指该进程在操作系统中的id,ppid是指他的父进程的id。
大致如下:

struct pcb{
	pid_t pid;
	pid_t ppid;
	//各种属性
};

这个pit_t是一个整型类型。

2.父进程与子进程的简单认识

操作系统中的父子进程,首先子进程中会有ppid来记录他的父进程id。而且子进程会将父进程的一些成员变量赋值给自己。
当我们编译好一个可执行程序执行他以后,我们会在进程中看到他。
在这里插入图片描述
让我们来多次重复运行这个程序。
在这里插入图片描述
在这里插入图片描述

我们发现,这个程序的pid一直在变化,但是ppid没变,说明他的父进程一直是同一个,我们现在找到这个进程。
在这里插入图片描述
发现他是-bash,也就是我们的命令行解释器。从命令行运行的程进程都是bash的子进程
那我们除ps命令外,还有什么方法可以查看系统中的进程呢?
在Linux系统中有一个proc文件夹,里面就存放着所有的进程文件夹,文件夹中记录着进程的各种数据。又因为进程是一直在变化的,那么这个proc文件夹中的内容也一直在变化.
在这里插入图片描述
我们运行自己的程序,看看这个文件的关于我们的程序里面有什么。
在这里插入图片描述

这里面我们需要知道几个内容

一个是exe,它能让进程知道可执行程序在哪里(磁盘中)存储
一个是是cwd,它记录了程序的当前目录。
	当前目录:我们写C语言进行文件io的时候,有过绝对路径和当前工作目录的概念,所以当前工作目录是我们不填写绝对路径时,默认创建文件的地方。这里一般是和自己的可执行程序在一个目录下。
还有一个命令,chdir,它可以修改当前工作目录

3.系统调用函数

Linux系统给了三个系统调用函数,getpid和getppid和fork。

1). getpid,getppid

在这里插入图片描述
他说这个函数调用不会失败也给了相应的头文件。现在我们来试试这两个函数。

int main()
{
  pid_t pid = getpid();
  pid_t ppid = getppid();
  printf("我是一个进程,我的id是:%d,我的父进程的id是:%d\n", pid, ppid);             
  return 0;
}

在这里插入图片描述

2). fork

a. fork简单认识

  Linux中创建进程可以从命令行创建,也可以通过代码来创建进程。这就是第三个要知道的系统调用接口,fork。
在这里插入图片描述
  他会在执行到他之后,创建一个关于这个可执行程序形成的进程的子进程。并且这个子进程的pcb里有一些属性是直接拷贝的父进程的
  他会返回两个值。返回给父进程子进程的id,返回给子进程0,如果创建进程失败,则会返回小于0的数。
我们来演示一下:

int main()
{
  printf("我是一个进程我的id是:%d\n", getpid());                                         
  fork();
  printf("hello world\n");
  return 0;
}

在这里插入图片描述
  我们会看到一个现象,第一句程序执行了一遍,第三句竟然执行了两遍,这是一个没有见过的情况。
我们对代码稍加改造:

int main()
{
  printf("我是一个进程我的id是:%d\n", getpid());
  fork();
  printf("hello world,我的id是:%d, 我的父id是:%d\n", getpid(), getppid());               
  return 0;
}

在这里插入图片描述

  这个3078进程是bash,我们也知道fork会创建新的进程,那么现在知道这个新的进程是当前程序的子进程。fork函数执行之后创建好的子进程会和父进程一起执行之后的程序(这个由cpu中寄存器的eip实现,eip是用来记录将要执行的代码的地址的),而fork之前只由父进程执行
我们发现fork还有返回值,让我们稍加改造上面的代码,看看这个返回值。

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

int main()
{
  printf("我是一个进程我的id是:%d\n", getpid());
  pid_t id = fork();
    printf("hello world,我的id是:%d, 我的父id是:%d,我的返回值是:%d\n", getpid(), getppid(), id);                    
  return 0;
}

在这里插入图片描述
  我们发现同一个变量竟然会出现不一样的结果,那么显然是fork竟然有两个返回值,给父进程返回子进程的pid,给子进程返回0,这显然是不符合我们之前的认知的。还有就是fork失败后会返回小于0的数。这是为什么我们之后再谈,我们先来谈谈,它的返回值能干什么?

b. fork的用法

  我们知道fork可以用代码创建进程,而且是他当前进程的子进程,对于两个进程有着不同的返回值。我们创建子进程的目的一定是因为单个进程无法完成任务,所以我们需要两个进程来完成我们所需要的任务。比如边下载边播放,那如何保证每个进程都做着正确的自己的事呢?别忘了我们可是有两个返回值的。我们用代码来演示一下:

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

int main()
{
  printf("我是一个进程,我的id是:%d,我的父进程是:%d\n", getpid(), getppid());


  pid_t id = fork();
  if(id < 0)
    return -1;
  else if(id == 0)
  {
    while(1)
    {
      printf("我是一个子进程我的id是:%d,我的父进程id是:%d,我正在执行下载任务\n", getpid(), getppid());
      sleep(1);
    }
  }
  else
  {
    while(1)
    {
      printf("我是一个父进程我的id是:%d,我的父进程id是:%d,我正在执行播放任务\n", getpid(), getppid());
      sleep(2);
    }
  }
  return 0;
}

在这里插入图片描述

c. fork的原理

  我们认识fork之后肯定有一个非常大的疑惑,那就是一个函数有两个返回值。接下来我们来详细说明一下fork背后的原理。

fork干了什么?

  我们知道一个程序被运行,是程序先被加载到内存中然后操作系统生成对应的pcb结构体然后再把这个结构体链入到运行队列中。那假如代码中有fork,那他就会再创建一个进程。那就意味着操作系统会再生成一个pcb结构体,再把他链入到运行队列中。那么就会有两个pcb指向同一个代码段,我们也知道,进程 = 代码 + 进程pcb,而代码又包含代码段和运行代码时产生的数据,所以说倒不如详细一点:进程 = 代码段 + 代码数据 + 进程pcb。对于两个进程他们的代码可能相同但是他们产生的代码数据不一定相同,所以当我们用fork创建好子进程后,生成的代码数据肯定是父进程一份,子进程一份,而这里操作系统采用的方法是写时拷贝,具体什么是写时拷贝,有兴趣可以看一下我的另一篇博客:用了写时拷贝的思想。

那为什么fork会返回给父进程子进程的pid呢?

这是因为父子关系是一对多的关系。父进程需要知道每个子进程的存在,而子进程只需要知道自己和父进程就可以。

fork为什么会返回两个值?

  现在我们再来研究一个普通的函数:当一个函数执行到return的时候意味着什么?意味着这个函数已经把他该做的任务已经完成了,接下来只需要返回关于他所产生一个数据就可以。那么对于fork这个系统调用接口来说也是一样,他也是一个函数,当他执行到return的时候,说明他创建子进程的任务已经完成了,fork之后,代码共享。那就说明从return开始父子进程就开始一起执行代码了。这就是为什么return会有不同的返回值了。

为什么一个变量会存储两个不同的值呢?

  肯定有人会说因为代码执行了两次,那变量名是一样的,执行之后代码要使用接收返回值的变量的时候,操作系统怎么就知道它使用的是谁返回呢?那我们再看看这个变量的地址:

在这里插入图片描述
在这里插入图片描述
他的地址竟然是一样的!!!

关于这个问题我们日后再讨论。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1104611.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【2023集创赛】信诺达杯三等奖:关于LM386N-1音频功率放大器性能的测量指南

本文为2023年第七届全国大学生集成电路创新创业大赛&#xff08;“集创赛”&#xff09;信诺达杯全国三等奖作品分享&#xff0c;参加极术社区的【有奖征集】分享你的2023集创赛作品&#xff0c;秀出作品风采&#xff0c;分享2023集创赛作品扩大影响力&#xff0c;更有丰富电子…

牛客:FZ35 滑动窗口最小值

FZ35 滑动窗口最小值 文章目录 FZ35 滑动窗口最小值题目描述题解思路题解代码 题目描述 题解思路 遍历数组&#xff0c;然后遍历窗口找到最小值&#xff0c;加入到结果集里面 题解代码 func minSlidingWindow( nums []int , k int ) []int {// write code heren : len(nums…

基于内存的分布式NoSQL数据库Redis(五)数据存储与RDB设计

文章目录 知识点18&#xff1a;数据存储设计知识点19&#xff1a;Redis持久化&#xff1a;RDB设计知识点20&#xff1a;Redis持久化&#xff1a;RDB测试后记 知识点18&#xff1a;数据存储设计 目标&#xff1a;掌握常见数据存储的设计 实施 问题 数据存储如何保证数据安全&am…

面试算法28:展平多级双向链表

问题 在一个多级双向链表中&#xff0c;节点除了有两个指针分别指向前后两个节点&#xff0c;还有一个指针指向它的子链表&#xff0c;并且子链表也是一个双向链表&#xff0c;它的节点也有指向子链表的指针。请将这样的多级双向链表展平成普通的双向链表&#xff0c;即所有节…

RocketMQ读写分离实战

这里是weihubeats,觉得文章不错可以关注公众号小奏技术&#xff0c;文章首发。拒绝营销号&#xff0c;拒绝标题党 背景 继上次分析RocketMQ线上各种system busy 比较合理能提升性能和缓解system busy的方法就是修改broker的配置为transientStorePoolEnable true 今天我们就…

慎投!包含Hindawi旗下2本,5本Scopus期刊被剔除!(附9月更新下载)

2023年9月Scopus期刊目录更新 Scopus官网近日更新了9月期刊目录&#xff0c;此次更新与上次&#xff08;2023年8月&#xff09;相比&#xff0c;有5本期刊不再被收录&#xff0c;详情如下&#xff1a; / Scopus期刊目录说明 / • SCOPUS 和 SCI 的相同点&#xff1a; 简单来说…

客户管理系统是如何提高工作效率的?

对于大部分企业来说销售部门相比市场营销等部门&#xff0c;会投入更大的人力、物力&#xff0c;客户管理系统在其中发挥着重要作用&#xff0c;它是如何提高工作效率的。 在数字化高度发达的今天&#xff0c;销售自动化已经步入了企业的经营管理中&#xff0c;大大地改善了销…

Spring Cloud Gateway集成Swagger实现微服务接口文档统一管理及登录访问

简介 本文将介绍如何在Spring Cloud微服务中使用Swagger网关来统一管理所有微服务的接口文档&#xff0c;并通过Spring Security实现登录后才能访问Swagger文档&#xff0c;以确保接口数据的安全访问。 在开始之前&#xff0c;需要假设你已经完成了Spring Cloud Gateway的相关…

触控笔哪个牌子好用?主动电容笔和被动电容笔的区别

主动式电容笔和被动式电容笔两者最大的不同之处在于主动式电容笔的应用范围更大&#xff0c;可以兼容各种不同的电容屏幕。随着人们对其认识的不断深入&#xff0c;其应用范围也在不断扩大。而且国产的主动式电容笔&#xff0c;也在不断的更新换代&#xff0c;重力越来越多&…

【工具】SecureCR-8.5下载、安装激活和使用教程

起初我参考的文章&#xff1a;【工具】SecureCR-8.5下载、安装激活和使用教程&#xff08;包含常用设置&#xff09;_securecrt激活_SecureCode的博客-CSDN博客 但是不行啊&#xff0c;执行到13步的时候报错&#xff1a; 问了作者也没有回应&#xff0c;直到我参考了&#xff…

动手实现H5仿原生app前进后退切换效果

动手实现H5仿原生app前进后退切换效果 前言 最近在优化H5页面&#xff0c;我注意到当开发完成的移动端H5页面嵌入到微信小程序或者原生app中时&#xff0c;当触发页面路由切换会与原生app看上去有点格格不入&#xff0c;因为H5页面<router-view>切换路由时是直接替换了…

vue3点击表格某个单元格文本就切换成输入框,其他单元格不变化

<el-table :data"data.tableData" height"60vh" border scrollbar-aways-on><el-table-column label"序号" type"index" width"80" fixed /><el-table-column label"操作" width"120" f…

Linux知识点 -- 高级IO(二)

Linux知识点 – 高级IO&#xff08;二&#xff09; 文章目录 Linux知识点 -- 高级IO&#xff08;二&#xff09;一、IO多路转接 -- poll1.poll接口2.poll实现3.poll优缺点 二、IO多路转接 -- epoll1.epoll接口2.epoll的工作原理3.epoll服务器实现4.epoll的优点5.epoll的工作模式…

在线加解密(支持SM2、SM3、SM4)

https://the-x.cn/zh-cn/cryptography/Sm4.aspx

SAS国际认证考试报名流程

文章目录 注册SAS账号登录SAS账号预约考试考试注意事项 注册SAS账号 SAS考试报名入口&#xff1a;https://home.pearsonvue.com/sas 注册SAS账号 邮箱验证 点击上述邮件发送来的链接&#xff0c;跳转到如下界面。输入密码即可。 完成注册。选择login。 登录SAS账号 输入Email …

MongoDB 未授权访问漏洞

简介 MongoDB是一个基于分布式文件存储的数据库&#xff0c;是一个介于关系数据库和非关系数据库之间的产品&#xff0c;它的特点是高性能、易部署、易使用&#xff0c;存储数据非常方便&#xff0c;默认情况下是没有认证的这就导致不熟悉它的研发人员部署后没有做访问控制导致…

NAND存储器转储分析 - 使用ECC修复位错误与UBI镜像固件分析

一、 简介 这篇研究论文将通过黑客的视角&#xff0c;详细阐述如何操作 NAND dump 以及如何获取 dump 文件中的所有文件。每一步骤以及所使用的方法均会细致解析&#xff0c;并配以实例说明。本文主要关注的是物理 NAND dump&#xff0c;这是从通用编程器中提取出的 dump 文件…

重磅!中科院1区TOP被踢?共7本被剔除!10月SCIE/SSCI期刊目录更新!

期刊动态&#xff1a;2023年10月SCI、SSCI期刊目录更新 2023年10月17日&#xff0c;科睿唯安更新了WOS期刊目录&#xff0c;继上次9月WOS期刊目录剔除7本SCIE&SSCI期刊之后&#xff0c;此次10月更新又有7本期刊发生变动&#xff0c;其中有5本SCIE期刊&#xff0c;1本SSCI期…

软键盘怎么打开?3招快速打开!

“我的键盘好像出现了一些问题&#xff0c;现在没法输入文字。听说电脑上有个工具叫软键盘&#xff0c;我想暂时先用这个来代替键盘。有什么方法可以把它打开的吗&#xff1f;” 软键盘是一个虚拟键盘&#xff0c;它不是物理键盘&#xff0c;而是出现在计算机屏幕上的可视化输入…

java的注解接口Target

java.lang.annotation.Target是Java中预定义的一个注解接口&#xff0c;用在注解接口的声明上&#xff0c;指明注解接口适用的上下文。 Target注解接口只有一个元素value&#xff0c;该元素的类型是java.lang.annotation.ElementType的数组&#xff0c;其中ElementType是一个枚…