目录
进程是如何被管理的
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的值呢。那么我们的操作系统同样也考虑到了如果父进程需要修改某个数据,可能会影响到子进程,但是如果直接拷贝一块空间出来给子进程使用,但是子进程使用了一点点岂不是会有很多的浪费。在这个问题上操作系统就想到一个办法,如果说某一个数据需要被修改,那么你就不要去原来的那块空间上去修改了,我给你重新开辟一块空间给你使用,至少这块空间的大小就是你要多少我就给你多少,这样的操作行为也被称为数据的写实拷贝。