进程创建(一)之 fork & vfork

一、进程创建(PCB、虚拟地址空间、页表、数据(映射关系加载好))
1、fork

fork可以从已有的进程中创建出一个新进程也叫作子进程,原来的那个进程就叫做父进程。一般,fork创建出子进程后,子进程一般是和父进程代码实现共享,数据实现写时拷贝的。

进程调用fork,当控制转移到内核中的fork代码后,内核会(1)将分配新的内存块和内核数据结构给子进程。(2)将父进程部分数据结构拷贝至子进程。(3)添加子进程到系统进程列表当中。(4)fork返回,开始调度器调度

  • fork的返回值:(这个我有在前面的博客中具体写过原因,可以戳此链接:https://blog.csdn.net/apt1203jn/article/details/79779888
    (1)子进程返回0;(2)父进程返回子进程的pid

  • fork的常规用法:(1)一个父进程希望复制自己,使得父子进程同时执行不同的代码段(eg:父进程等待客户端请求,创建子进程来处理请求)。(2)一个进程要执行一个不同的程序(eg:子进程从fork返回之后,调用exec函数 )

  • 调用fork失败的原因:(1)内存不够(2)实际用户的进程数超过了限制

2、vfork

vfork()创建子进程的特点:

* 子进程和父进程共享地址空间(fork的子进程具有独立的地址空间)
* vfork保证子进程先运行,在它调用exec或(exit)之后父进程才可能被调度运行         

测试用例:

(1)验证一下vfork()创建出的子进程会先于它的父进程调度运行(让子进程sleep一下使它的生命周期变长)

先写Makefile

.OPHNY:test

test:test.c
        gcc -o test test.c

.OPHNY:clean
        clean:
            rm -f test

test.c

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int g_val = 100;
int main()
{
      //pid_t id = fork();
      pid_t id = vfork();
      if (id == 0){
            printf("child, pid:%d, ppid:%d, g_val:%d,&g_val:%p\n", getpid(), get    ppid(), g_val, &g_val);
            sleep(3);
            exit(1);
      }
      else if (id > 0){
            printf("father, pid:%d, ppid:%d, g_val:%d,&g_val:%p\n", getpid(), ge    tppid(), g_val, &g_val);
            exit(2);
      }    
      return 0;
}

先来看一下调用fork()创建子进程的运行结果
这里写图片描述
注释掉fork(),看一下vfork()创建子进程之后的调度顺序
运行结果:
这里写图片描述
由图可见,vfork() 创建的子进程会先运行,在子进程调用exit函数之后父进程才可能被调度运行。
大家可以自行验证一下,我没有开另外的终端检测,所以运行效果不是非常非常明显,大家自己动手验证一下哦!

(2)验证父进程和子进程共用一块地址空间
test.c

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int g_val = 100;
int main()
{
      pid_t id = fork();
      //pid_t id = vfork();
      if (id == 0){
          printf("befor:child, pid:%d, ppid:%d, g_val:%d,&g_val:%p\n", getpid(), getppid(), g_val, &g_val);

          g_val = 200;
          printf("after:child, pid:%d, ppid:%d, g_val:%d,&g_val:%p\n", getpid(), getppid(), g_val, &g_val);

          sleep(1);
          exit(1);
      }
      else if (id > 0){
          printf("father, pid:%d, ppid:%d, g_val:%d,&g_val:%p\n", getpid(), ge    tppid(), g_val, &g_val);
      }
      return 0;
}

注:Makefile文件同上一个

下面是用fork()创建子进程的运行结果
这里写图片描述

于此可以看出,fork()创建出的子进程并没有直接改变父进程的变量值,那么vfork()创建出的子进程会不会改变父进程的变量值嘞?

下面放开vfork() 的注释,看一下运行结果
这里写图片描述
解析:
上图结果可见子进程直接改变了父进程的变量值,这主要是因为子进程在父进程的地址空间中运行。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值