乐清 网站建设,紫金网站建设,咨询网站设计,地方购物网站盈利模式目录 一.初识fork函数
二.fork的返回值
三.fork原理
1.fork是如何创建子进程的#xff1f;
2.为什么fork会有两个返回值#xff1f;
3.为什么父进程的返回值是子进程的pid#xff0c;子进程返回值是0#xff1f;
4.fork之后#xff0c;父子进程谁先运行#xff1f;…目录 一.初识fork函数
二.fork的返回值
三.fork原理
1.fork是如何创建子进程的
2.为什么fork会有两个返回值
3.为什么父进程的返回值是子进程的pid子进程返回值是0
4.fork之后父子进程谁先运行
5.如何理解同一个变量会有不同的值 一.初识fork函数
创建子进程的方式 1.在命令行上创建 2.在代码中使用fork创建 今天讲述的是fork创造子进程。
使用man手册查看fork 验证fork()创建了子进程
#includestdio.h
#includesys/types.h
#includeunistd.hint main()
{printf(我是一父个进程我的pid是%dppid:%d\n,getpid(),getppid());fork();printf(我是一个进程我的pid是%dppid:%d\n,getpid(),getppid());sleep(1);return 0;
}
观察图片注意pid与ppid 在写一个循环情况观察
#includestdio.h
#includesys/types.h
#includeunistd.hint main()
{printf(我是一父个进程我的pid是%dppid:%d\n,getpid(),getppid());fork();while(1){printf(我是一个进程我的pid是%dppid:%d\n,getpid(),getppid());sleep(1);}return 0;
} 从图中我们可以看出fork()之后的代码执行行了两次根据pid与ppid我们可以看出是两个不同进程执行的且可以分出那个是子进程那个是父进程 结论只有父进程执行了fork之前的代码fork之后父子进程都要执行后续代码 二.fork的返回值
fork函数的返回值
当创建子进程成功时 有两个返回值子进程的返回值是0父进程的返回值是子进程的pid 当创建子进程失败 有一个返回值小于0. 代码验证
#includestdio.h
#includesys/types.h
#includeunistd.hint main()
{printf(我是一父个进程我的pid是%dppid:%d\n,getpid(),getppid());pid_t idfork();while(1){printf(我是一个进程我的pid是%dppid:%d\n, id%d,getpid(),getppid(),id);sleep(1);}return 0;
} 为什么fork函数的返回值要有两个呢
这里我们就不得不提为什么创建子进程。
原因我们想要子进程协助父进程完成一些单进程解决不了的工作。如对于想要电影边下载边播放可能不恰当但有助于理解。 因此我们想要子进程与父进程执行不一样的代码。为了实现这个这个目的我们让fork的返回值有两个然后通过判断fork的返回值判断谁是父进程谁是子进程然后让他们执行不同的代码 代码实例
#includestdio.h
#includesys/types.h
#includeunistd.hint main()
{printf(我是一个父进程pid是%d\n,getpid());pid_t idfork();if(id0)return 1;else if(id0){while(1){//childprintf(我是子进程pid:%d, ppid:%d, id%d 正在执行下载任务\n,getpid(),getppid(),id);sleep(1);}}else{while(1){//parentprintf(我是父进程pid:%d, ppid:%d, id%d 正在执行播放任务\n,getpid(),getppid(),id);sleep(1);}}return 0;
}三.fork原理
1.fork是如何创建子进程的
我们知道
进程可执行文件内核数据结构PCB
在fork创建子进程时系统会多一个子进程。 1.在内存中为子进程malloc申请空间并以父进程为模板为子进程创建PCB并初始化对父进程的PCB进行局部拷贝 2.与父进程共享代码和数据.(这也是父子进程执行同样代码的原因) 这里我们知道了父子进程共享同一份代码与数据那么为什么子进程不会执行fork之前的代码呢 我们要知道程序之所以能够从上往下的顺序执行依靠的是CPU中存在的pc/eip程序计数器当执行进程时CPU会读取该进程的PCB里的pc/eip的值然后从对应的代码开始执行。而fork创建子进程后父进程的pc/eip指向了fork之后的代码而子进程的PCB在创建的时候刚好拷贝了父进程的pc/eip因此子进程不会执行fork之前的代码。 2.为什么fork会有两个返回值
这里问大家一个问题
如果一个函数已经执行到return了它的核心工作做完了吗
这里我们可以以swap(int* x,int* y)函数为例我们可以通过调试发现在函数执行到return的时候两个数的数值早已交换。
因此可以认为函数在执行到return时它的工作就已经做完了
而fork就是一个系统调用函数fork的工作如下 因此在fork执行到return的时候进已经完成了子进程的创建了。我们知道父子进程共享代码而return时代码因此return也被父子进程共享执行。
所以 父进程被调度就要执行return 子进程被调度也要执行return 3.为什么父进程的返回值是子进程的pid子进程返回值是0
这里我们举现实生活的例子
在现实生活中一个父亲可以有多个子女但是子女只有一个父亲。 父子1n所以我们有一个天然的需求父进程要管理子进程需要标识子进程的唯一性而子进程访问父进程时不需要的。而又由于子进程的pid具有唯一性因此采用了该方法 4.fork之后父子进程谁先运行
在创建完子进程之后系统的其他进程父进程和子进程接下来是要被调度的。
这里我们知道操作系统是依靠双链表来管理进程的PCB的。
当父子进程的PCB都被创建并在运行队列中排队时哪一个进程的PCB先被调度那个进程就先运行。 而那个进程先被调度在用户层面上是不清楚的因此我们并不知道父子进程谁先运行 因为它是由各自PCB中的调度信息时间片优先级调度器算法共同决定完完全全又操作系统自主实现 5.如何理解同一个变量会有不同的值
这里由于牵扯到地址空间会在地址空间详细解释这里只是一个开头 在前面我们知道fork在成功创建子进程时两个返回值。但是这里我们使用一个变量接受的为什么一个变量会有不同的值
这里我们先说一个现象。
如果启动一个QQ微信浏览器。这些都是进程如果杀掉微信进程QQ进程浏览器进程还在吗当然还在。
如果父子进程中父进程被杀掉子进程还在吗或者反过来。
实例
#includestdio.h
#includesys/types.h
#includeunistd.hint main()
{printf(我是一个父进程pid是%d\n,getpid());pid_t idfork();if(id0)return 1;else if(id0){while(1){//childprintf(我是子进程pid:%d, ppid:%d, id%d 正在执行下载任务\n,getpid(),getppid(),id);sleep(1);}}else{while(1){//parentprintf(我是父进程pid:%d, ppid:%d, id%d 正在执行播放任务\n,getpid(),getppid(),id);sleep(1);}}return 0;
}父进程被杀掉子进程不受影响仍可以正常运行 原因进程进程之间运行的时候是具有独立性的无论是什么关系! 父子进程如何做到独立性互不影响 进程可执行文件内核数据结构PCB 1.父子进程有各自的PCB 2.由于代码是只读的不会影响数据数据父子是可以修改的。所以代码共享数据各个进程要想办法私有一份。 而数据又是如何让私有的呢 这里操作系统为了效率采用了写时拷贝。 写时拷贝在不修改数据时父子进程共享数据一旦修改数据就会为修改数据的进程重新开辟空间存储数据。 因此根据上述现象总结 在fork函数的return处子进程就创建完毕开始共享代码与数据而对于 idfork(); 这段代码本质就是修改数据因此发生写时拷贝所以同一个变量会有不同的值 那么具体是如何让一个变量的可以有两个值呢
可能会有人觉得只是变量名相同地址不同。
这里我们可以用上面的代码将id打印出来验证。 这里我们可以看出并不是的。
但是我们学过C语言我们可以明确知道同一块地址空间是不可能有不同内容的。
因此我们可以确定id的地址绝不是物理地址
接下来的内容由于牵扯到地址空间的内容今天就讲到这里还会在地址空间处详细讲解。