16 进程创建

本文详细解释了Linuxfork函数的工作原理,包括如何创建子进程、子进程的数据来源、EIP和程序计数器在进程切换中的作用,以及写时拷贝技术确保进程间数据独立性。同时讨论了fork的返回值和常见用法,以及fork失败可能的原因——进程数量过多。
摘要由CSDN通过智能技术生成

fork函数

在linux中fork函数是非常重要的函数,从已存在的进程中创建一个新进程。新进程为子进程,原型为父进程

#inlucde <unistd.h>
pid_t fork(void);
返回值: 自进程中返回0,父进程返回子进程id,出错返回-1

fork函数做了什么

子进程的代码数据从哪来
fork创建子进程后系统里多了一个进程,进程=内核数据结构+进程代码和数据,子进程的数据结构是基于父进程的复刻,代码和数据一般都是从磁盘里来的,也就是c/c++冲虚加载后的结果。分配的内核结构子进程独有了,因为进程具有独立性。子进程没有自己的代码和数据就是没意义的。所以,子进程只能使用父进程的代码和数据

进程调用fork,控制转移到fork内核中的代码后,内核做:

  • 分配新的内存块和内核数据结构给父进程
  • 将父进程部分数据结构内容拷贝至子进程
  • 提那家子进程到系统进程列表当中
  • fork返回,开始调度器调度

子进程运行内容

在这里插入图片描述

在这里插入图片描述

当一个进程调用fork之后,就有两个二进制代码相同的进程,而且他们都运行到相同的地方。每个进程都可以开始它们自己的运行,看如下程序:

int main( void )
{
 pid_t pid;
 printf("Before: pid is %d\n", getpid());
  if ( (pid=fork()) == -1 )perror("fork()"),exit(1);
 printf("After:pid is %d, fork return %d\n", getpid(), pid);
 sleep(1);
 return 0;
} 
运行结果:
[root@localhost linux]# ./a.out
Before: pid is 43676
After:pid is 43676, fork return 43677
After:pid is 43677, fork return 0

这里看到了三行输出,一行before,两行after。进程43676先打印before消息,然后打印after。另一个after消息有43677打印的。注意到进程43677没有打印before,为什么呢

在这里插入图片描述

运行的结果,父进程执行了before的代码,fork后父子进程都输出了after的信息,也就是执行了fork后的代码

为什么子进程在after处执行
fork创建子进程后,父子的所有代码都是共享的,fork之前的代码子进程也是拥有的。但子进程只会接着fork之后运行。这是因为一个程序在执行的过程中怎么知道运行到了哪里

我们的代码汇编之后,会有很多代码,每行代码加载到内存后,都有对应的地址。因为进程随时会被中断,这时并没有执行完,所以要求cpu必须知道执行到的位置。所以,cpu中有一个EIP寄存器,叫pc程序计数器,记录了正在执行代码的下一行代码的地址,它永远指向下一条需要执行的代码。寄存器在cpu内只有一份,而寄存器内的数据可以有很多份,所以这个地址就成了进程的上下文数据

这个上下文数据在子进程创建后也要给子进程,虽然父子进程各自调度,各自修改EIP,但不重要了,因为子进程是父进程EIP的初始值,也就是fork后的代码位置

写时拷贝

代码是只读的,父子进程可以共享。但是如果子进程可以修改父进程的数据,那么就破坏了进程间独立性的原则,所以,两个进程必须分离

1.对于数据而言,创建进程的时候,就直接拷贝分离吗?这时,如果拷贝了子进程根本不会用到的数据空间,而且即使用到了也可能只是读取,不会访问和修改写入,这样会造成空间的浪费

在这里插入图片描述
我们创建两个字符串常量的时候,str和str1的地址是一样的,因为用的都是“aaa
”这个常量,常量是不会修改的,所以只需要共用一个内容,编译器尚且知道节省空间,那操作系统怎么做呢

2.对于会修改的数据,在子进程创建之后就立马拷贝一份吗?如果不是立马就会使用的数据,过很久才会使用,还是造成了资源的浪费

3.一般而言,操作系统也无法提前知道哪些空间可能会被写入

在这里插入图片描述
在这里插入图片描述

所以,OS采用了写时拷贝的技术,当父子进程对某个值写入的时候,会将这个数据再拷贝一份,这样对数据分离,就保证了进程间的独立性。又保证了资源的有效利用。string的深浅拷贝也是这个技术

因为有写时拷贝的存在,父子进程得以彻底分离,完成了进程独立性的技术保证,写时拷贝,也是一种延时申请技术,可以提高整机内存的使用率

fork返回值

子进程返回0
父进程返回子进程的pid

fork常规用法

一个父进程希望复制自己,使父子进程执行不同的代码段,例如,父进程等待客户端要求,生成子进程来处理请求
一个进程要执行一个不同的程序,例如子进程从fork返回后,调用exec函数

fork失败的原因

系统中有太多的进程
实际用户的进程数超过了限制

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值