007 Linux fork()函数

前言

本文将会以提问的形式展开向你介绍fork函数

文章重点

关于fork函数,本文重点在于解决以下疑问

疑问一:
为什么fork之前的代码只有父进程执行,然而fork之后的代码父子进程都要执行
疑问二:
1、既然fork之后父子进程会执行一样的代码,那么子进程的意义是什么?
2、为什么fork的两个返回值,会给父进程返回子进程的pid,给子进程返回0
疑问三:
1、为什么fork会有两个返回值
2、如何理解同一个变量,会有不同的值
3、fork之后,父子进程谁先运行

引入fork()函数

linux系统是用c语言写的,所以在linux中创建一个进程实际上也要调用c语言的函数也就是用代码创建进程叫做系统调用,fork函数是Linux系统中实现多进程编程的基础,通过fork函数,可以创建一个子进程,然后在子进程中执行不同的任务,从而实现并行计算和多任务处理。

fork解析一

使用man指令查看fork函数信息
007 Linux fork()函数_第1张图片

#include    
#include    
#include    
int main()    
{    
    printf("我是一个进程,pid:%d ppid:%d\n",getpid(),getppid());                                                                                                         
    while(1)    
    {              
        fork();                                                          
        printf("i am a process,pid:%d ppid:%d\n",getpid(),getppid());    
        sleep(1);    
    }       
    return 0;
}   

观察结果
在这里插入图片描述
可以观察到子进程已经被创建出来了(pid为5584)

疑问:为什么fork之前的代码只有父进程执行,然而fork之后的代码父子进程都要执行(观察结果的后两行->父子进程都执行了代码),并且为什么子进程不会从头开始执行父进程的代码?

原因是: 子进程以父进程为模板,把父进程中的大部分属性拷贝给子进程
fork会创建子进程,系统中会多出一个子进程,操作系统以父进程为模板为子进程创建PCB,但是创建的子进程是没有代码和数据的!!目前和父进程共享代码和数据
所以fork之后,父子进程会执行一样的代码,创建出来的子进程并不从头开始执行父进程的代码,而是从fork函数之后的代码开始执行(父进程的大部分属性拷贝给了子进程,包括寄存器的状态->用于记录当前指令的执行位置和保存临时数据)

fork解析二

观察第二第三行分别是父进程和子进程执行的结果
在这里插入图片描述

疑问二:
1、既然fork之后父子进程会执行一样的代码,那么子进程的意义是什么?
2、为什么fork的两个返回值,会给父进程返回子进程的pid,给子进程返回0

引入: fork成功的时候会有两个不同的返回值,给子进程返回0,给父进程返回子进程的pid
为什么要创建子进程呢:我们想让子进程协作父进程完成一些工作,这些工作是单进程解决不了的
可以通过判断fork的返回值,来让父子进程执行不一样的代码,让子进程实现和父进程不一样的功能,比如:我们可以一边玩游戏一边听着音乐,这两个过程就是不同的进程在执行

#include                                                                                                                                                       
#include    
#include    
int main()    
{    
    printf("我是一个父进程,我的pid是: %d\n",getpid());    
    
    pid_t id = fork();    
    
    if(id==0)//子进程的代码片段    
    {    
        while(1)    
        {    
            printf("我是子进程: pid:%d ppid: %d ret:%d,我在进行下载任务\n",getpid(),getppid(),id);    
            sleep(1);    
        }    
    }    
    else if(id>0)//父进程的代码片段    
    {    
    
        while(1)    
        {    
            printf("我是父进程: pid:%d ppid: %d ret:%d,我在进行播放任务\n",getpid(),getppid(),id);    
        sleep(1);    
        }    
    }
    return 0;
}

pid_t id = fork();
观察结果:fork成功的时候会有两个不同的返回值,给子进程返回0,给父进程返回子进程的pid
在这里插入图片描述

一个父进程可以创建很多个子进程,然而一个子进程只对应一个父进程,所以fork函数会返回子进程的id给父进程,方便父进程管理它的子进程

fork解析三

1、为什么fork会有两个返回值
2、如何理解同一个变量,会有不同的值
3、fork之后,父子进程谁先运行

007 Linux fork()函数_第2张图片

1、创建完子进程后,子进程会共享父进程的代码和数据,很明显return也是一句代码,所以父子进程都会执行return语句,fork函数有两个返回值

pid_t id = fork();
打印id地址
在这里插入图片描述
观察到父子进程的返回值id是不一样的,但是地址却是一样的。
怎么可能同一个变量,同一个地址,会有不同的内容(变量id在父进程和子进程中值不同)呢?

2、进程具有独立性,首先表现在进程各自的PCB运行时不会相互影响,很明显,代码本身只是可读的,所以不是影响代码,但是对于数据来说,父子的数据是可能不同的(可能会被修改)
所以系统是怎样做到让数据在各个进程都自己私有一份的,答案是写时拷贝,数据会在需要使用时被写时拷贝到PCB,然而fork返回值赋值给变量时,本质也是写入,返回时也会发生写时拷贝,所以不同的进程执行的代码中的变量id获取的值不同

3、那么fork之后,父子进程谁先运行?
在调度队列中,cpu会选择一个进程去运行它,谁先被调度谁先运行,所以fork之后父子进程谁现在运行是不确定的,这是由各自进程PCB中的调度信息决定的,比如优先级,算法信息等。

小结

今日的分享就到这里啦,后面将会向你带来进程的状态,优先级,进程地址空间等知识,如果本文存在疏漏或错误的地方还请您能够指出!
007 Linux fork()函数_第3张图片

你可能感兴趣的:(linux,linux)