浅入深出充分理解-->(fork())父子进程

1 篇文章 0 订阅
1 篇文章 0 订阅

目录

进程是如何被管理的

Linux下的进程是如何被管理的

fork()父子进程的创建

1:为什么fork返回给父进程子进程的id,给子进程返回0

2:一个函数是如何做到返回两次的

3:一个变量怎么会有不同内容


在某一个时刻,我正在用电脑打开某个软件进行操作,可是突然这个软件卡死了,在长时间的苦等之下我终于忍受不了,唤出任务管理器就要去结束这个任务。当任务管理器被打开的那一刻,就能看到各种各样的进程,那么这些进程是如何产生的呢。这里将和大家一起来探讨学习

进程是如何被管理的

当我们打开电脑对其使用的时候,可以一边听歌,一边打游戏,一边聊天,这都归功于我们的操作系统,那么操作系统是如何办到的呢。

比如在我们的学校中,有校长,辅导员,学生。校长对辅导员说今年我们的学校要组织一个篮球的队伍去参加市里面的篮球比赛,身高要选取最高的那几个,然后你的辅导员拿到这个消息就开始对班内的学生进行筛选,然后辅导员在把选出来符合要求的一批人的信息在交给校长。这个信息里面就包括你这个人身高,年龄,体重等的各种各样的信息,校长在按照摆放的顺序由上至下的进行筛选。那么在完成这个过程中,校长是从来没有见过你的,他只是拿到你的信息就足够了解到你这个人是怎么样的。最后当你被确认入选的时候你才会去篮球场进行训练。

那么同样,一个程序在真正成为进程之前操作系统会把它的各种各样的信息描述起来,这样的的行为被称为PCB(process ctrl block)-->进程控制块。但是我们的电脑不可能只有一个进程,当进程需要被加载到内存中之前,操作系统会根据进程的PCB,为该进程创建对应的PCB,PCB被创建出来之后会由PCB在指向这个进程中的代码和数据。如果我后来想要删除一个进程,那么这个进程该如何被找到呢。操作系统会把PCB用链表的形式链接起来,当我们需要退出一个进程的时候,实际上就是对链表进行的一个删除操作,所以对进程的操作也就变成了对链表的增删改查。

 PCB的本质其实就是进程的属性数据,操作系统的管理实际上是对数据属性的管理。

Linux下的进程是如何被管理的

当我们了解了Windows下的进程是如何被管理的之后再来看看Linux下的进程又是如何被管理的。首先在Linux下的进程被称为task_struct。现在我们在Linux下简单写一下一份代码    

 然后让它运行起来并且去去查看一下它是否真的存在当前进程

 从这里确实看到这个程序运行起来了,并且这个程序上面有两个叫PPID,PID的东西。那么这个其实就是子进程ID和父进程ID了。那么什么是子进程什么又是父进程呢。

fork()父子进程的创建

我们这里认识一个函数叫fork()。先去看一下fork的介绍

 这里大概讲到fork()会去赋值调用来创建一个新的进程被称为子进程,被调用的哪个进程被称为父进程,

 

然后在去看一下返回值,这里的返回值提到的是如果成功了会给父亲返回子进程的id,给子进程返还0,失败的话会返回-1。根据这个条件我们可以写下这样几行代码

通过这样一段代码可以看到,for之后的语句被调用了两次,原因就是因为父进程回创建一个子进程,fork之后父子都会执行一次就打印了两次。

在简单了解了fork()之后我们再来看这样一段代码并通过执行它又能发现什么不一样的

 通过对比这段代码我们似乎发现了一个不同寻常的地方,根据以往我们所学的经验,一份.c文件中的两个死循环同时被执行到了.似乎有点不符合我们以往所学的逻辑。那么这里不仅会有几个疑问

1:为什么fork返回给父进程子进程的id,给子进程返回0

返回不同的值是因为为了让不同的执行流执行不同的代码,在一个文件中,有时候我们会想在某个阶段通过不同的值来执行不同的代码。并且一个父进程可能不只有一个子进程,在多个子进程的情况下用来区分当前是哪一个子进程

2:一个函数是如何做到返回两次的

  在此之前我们需要先了解,fork创建出来的子进程和父进程是共享一块代码的。在调度fork之前会,父进程会有自己的ppid(父进程编号)和pid(子进程编号)数据和代码,cpu可以直接去调度父进程,当fork创建出来子进程之后,子进程也会有自己的ppid和pid数据和代码,但是只有父进程的代码和数据没有子进程的,那么此时子进程就会和父进程指向同一块代码。那么我们在回到fork身上,在调用了fork之后就能简单理解此时的frok内部其实做了一些诸如这样的操作

创建子进程PCB

填充PCB

让父子进程指向同一块代码

父子进程都有task_struct,可以被cpu调度了

最后在return一个值回去。那么此时子进程已经被创建,因为父子进程共享一块代码,所以在父进程return之后,子进程也同样会执行return。

 

 

3:一个变量怎么会有不同内容

刚刚我们说到,父子进程共享一块代码,那么既然共享一块代码那么它们的数据怎么可以一会是大于0的值一会又是等于0的值呢。那么我们的操作系统同样也考虑到了如果父进程需要修改某个数据,可能会影响到子进程,但是如果直接拷贝一块空间出来给子进程使用,但是子进程使用了一点点岂不是会有很多的浪费。在这个问题上操作系统就想到一个办法,如果说某一个数据需要被修改,那么你就不要去原来的那块空间上去修改了,我给你重新开辟一块空间给你使用,至少这块空间的大小就是你要多少我就给你多少,这样的操作行为也被称为数据的写实拷贝。

 

  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
### 回答1: Linux中的fork()函数可以创建一个新的进程,这个新进程是原进程的副本,也就是说,它们有相同的代码、数据和堆栈。fork()函数会返回两次,一次是在父进程中返回子进程进程ID,另一次是在子进程中返回。父进程和子进程之间的区别在于它们的进程ID不同,以及它们的父进程ID也不同。父进程和子进程共享文件描述符、信号处理程序和文件锁等资源,但是它们各自拥有自己的地址空间和堆栈。 ### 回答2: Linux中fork()是创建进程的一个系统调用,fork()会复制一份父进程的全部资源,包括代码段、数据段、堆栈、打开的文件、进程组信息等都会被复制到子进程中。因此,原来父进程有的资源,在子进程中都会有一个副本。fork()调用成功后,会返回两次,一次是在父进程中返回子进程的PID,另一次是在子进程中返回0。 在fork()调用完成后,就会现两个进程:父进程和子进程。父进程中的所有资源都被完全复制到了子进程中,但子进程具有独立的内存空间和进程ID,因此父进程和子进程之间的内存空间是互相独立的。在这种情况下,父进程和子进程执行的代码相同,但是子进程是一个全新的进程,具有自己的内存空间和进程上下文。 如果子进程想和父进程之间进行通信,可以使用管道或者共享内存。透过管道或共享内存,子进程可以读取父进程中的数据,或者将自己产生的数据发送给父进程。另外,还可以使用信号或者消息队列进行通信。 需要特别注意的是,fork()调用成功后,子进程中会复制父进程中的所有资源,包括打开的文件描述符等。因此,子进程需要关闭不需要的文件描述符,避免浪费系统资源。此外,子进程也需要确保在调用exec()函数之前,所有需要使用的文件描述符都已经打开了,否则在子进程中打开的文件描述符可能会覆盖父进程中已经打开的文件描述符,导致现错误。 ### 回答3: 在Linux系统中,每个进程都有一个唯一的进程ID(PID),以及一些其他的属性和信息。除了在启动时由init进程创建的特殊进程以外,每个进程都是由另一个进程fork来的,即在原有进程的基础上创建一个全新的进程。 在C语言中,可以使用fork()函数来实现这个操作。每次调用fork()函数时,会创建一个全新的进程,称为“子进程”,并且这个子进程就是由“父进程fork来的。父进程和子进程在大部分方面都是相同的,例如二者运行相同的程序、拥有相同的内存空间和变量等等,但在某些方面也有一些差异,例如二者的进程ID不同(父进程进程ID就是调用fork()函数前的进程ID,而子进程进程ID是新分配的),以及二者对共享资源的访问方式不同(具体取决于程序的实现方式)。 通常情况下,fork()函数的返回值为0,表示子进程;或者返回一个大于0的数值,表示父进程,并且这个数值就是子进程进程ID。如果fork()函数返回一个负数,则表示创建子进程失败。 在实际编程中,可以利用fork()函数来实现一些复杂的应用,例如多进程并行计算、进程间通信等等。此外,fork()函数也是Unix/Linux系统中一种重要的机制,可以实现进程的动态创建和销毁,从而增强了系统的灵活性和可扩展性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值