创建进程fork——父进程与子进程

fork创建进程

fork系统调用是用于创建进程的,由fork创建的新进程被称为子进程。
父进程和子进程继续执行fork调用之后的指令。子进程是父进程的副本。例如,子进程获得父进程数据 空间、堆和栈的副本。注意,这是子进程所拥有的副本。父进程和子进程并不共享这些存储空间部分。父进程和子进程共享正文段。

  1. fork系统调用无参数。pid_t fork(void)
  2. fork被调用一次,但返回两次。两次返回的区别在于子进程的返回值是0,父进程的返回值是子进程的ID。
  3. 将子进程ID返回给父进程的理由是:因为一个进程的子进程可以有多个,并且没有一个函数可以获得其所有子进程的进程ID。将0返回给父进程的理由是:因为一个子进程的父进程只有一个,并且可以通过getppid()函数来获得父进程ID(进程ID 0 总是由内核交换进程使用,所以一个子进程的进程ID不可能为0.)

测试代码

#include <cstring>
#include <stdio.h>
#include <unistd.h>

int main(){
        pid_t pid;
        int i=0;

        pid = fork();
        if(pid == 0){
                while(1){
                        i = i-1;
                        printf("%d, son process\n",i);
                        }
                }
        else if(pid>0){
                while(1){
                        i = i+1;
                        printf("%d, father process\n",i);
                        }
                }
        else{printf("failed in creating son process");}
        return 0;
}

执行命令:

gcc fork_demo.cpp fork_demo -g -lpthread

测试结果:
在这里插入图片描述
从这里可以分析结果得出

  1. 父进程和子进程开始的变量的值是相同的,我理解的是子进程开辟了自己的一块资源空间,然后把父进程的变量copy过去,所以后面++和–都是针对各自进程中的值。
  2. 我认为就是父进程和子进程其实就是两个并行的进程(这里指的并行是想说明每个进程都是独立的)

在《APUE》一书中说道:

一般来说,在fork之后是父进程先执行还是子进程先执行是不确定的,这取决于内核所使用的调度算法。如果要求父进程和子进程之间相互同步,则要求某种形式的进程间通信。
由于在fork之后经常跟随着exec,所以现在的很多实现并不执行一个父进程数据段、栈和堆的完全副本,作为替代,使用了”写时复制“(Copy-on-write,COW)技术。这些区域由父进程和子进程共享,并且内核将他们的访问权限改为只读。如果父进程和子进程中的任一个试图修改这些区域,则内核只为修改区域的那块内存制作一个副本,通常时虚拟存储系统中的一”页“。

书上的说法和我的猜想有一些不太一致,因此我在修改i值之前对i进行了取地址运算,再对比一下修改之后的地址,看下书上说的是否正确。

验证程序:

#include <cstring>
#include <stdio.h>
#include <unistd.h>

//using namespace std;

int main(){
        pid_t pid;
        int i=0,j;
        printf("[before] %p\n",&i);
        pid = fork();
        if(pid == 0){
                for(j=0;j<5;j++){
                        i = i-1;
                        printf("[child] %p\n",&i);
                        printf("%d, son process\n",i);
                        }
                }
        else if(pid>0){
                for(j=0;j<5;j++){
                        i = i+1;
                        printf("[father] %p\n",&i);
                        printf("%d, father process\n",i);
                        }
                }
        else{printf("failed in creating son process");}

        return 0;

}

在这里插入图片描述
before是修改之前的地址,father是父进程修改后的i的地址,child是子进程修改后的i的地址。

看了一位博主的博客上面说是物理空间在写操作之后发生了变化。应该是逻辑空间没变。。

  • 9
    点赞
  • 40
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值