• Linux:fork()函数


    fork()系统调用会通过复制一个现有进程来创建一个全新的进程。进程被存放在一个叫做任务队列的双向循环链表中,链表中的每一项都是进程PCB。

    fork()运行时做的事情

    #include<stdlib.h>
    #include<unistd.h>
    #include<stdio.h>
    
    int main()
    {
        printf("leetcode
    ");
        pid_t pid = fork();
        if(pid == -1)
            printf("error in fork!");
        printf("pid = %d, returnVal = %d
    ", getpid(), pid);
        return 0;
    }
    /*
    运行结果:
    leetcode
    pid = 22754, returnVal = 22755
    pid = 22755, returnVal = 0
    注意:
    */
    

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

    1.分配新的内存块和内核数据结构给子进程

    2.将父进程部分数据结构内容(数据空间,堆栈等)拷贝至子进程

    3.添加子进程到系统进程列表中

    4.fork()返回,开始调度器调度

    为什么fork()成功调用后返回两个值?

    由于在复制时复制了父进程的堆栈段,所以两个进程都停留在fork函数中,等待返回。所以fork函数会返回两次,一次是在父进程中返回,另一次是在子进程中返回,这两次的返回值不同,其中父进程返回子进程pid,而子进程返回0。

    从fork函数开始以后的代码父子共享,既父进程要执行这段代码,子进程也要执行这段代码.

    父子进程文件共享问题

    子进程是父进程的副本。例如,子进程获得父进程数据空间、堆和栈的副本。注意,这是子进程所拥有的副本。父进程和子进程并不共享这些存储空间部分。父进程和子进程共享正文段。

    fork后子进程和父进程共享的资源还包括:打开的文件

    fork()和vfork()的比较

    vfork()的诞生是在fork()还没有写时拷贝的时候,因为那个时候创建一个子进程的成本太大了,如果一下子创建好多那么程序的效率一定会下降。

    vfork()的实现原理非常简单,就是子进程,父进程完全共用一个资源。即使有人修改了内容,甚至main()函数退出了也不会新开辟一个空间。

    fork()和vfork()之间的区别

    1.fork父子进程交替运行,vfork保证子进程先运行,父进程阻塞,直到子进程结束(或子进程调用了exec或exit)

    2.fork实现了写时拷贝; 而vfork直接让父子进程共用公用资源,避免多开辟空间拷贝

    3.vfork必须使用exit或者excl退出

    4.就算是fork使用了写时拷贝,也没有vfork性能高

    僵尸进程和孤儿进程

    在进程结束后,Linux系统会自动回收进程消耗的 内存和IO,但是进程本身占用的资源(task_struct和栈内存)不会被回收,需要被父进程来进行回收

    僵尸进程:子进程比父进程先结束!如果父进程没有显式调用wait或waitpid函数的话,直到父进程结束时才会回收子进程的资源!这样的子进程,就是僵尸进程!

    孤儿进程:父进程先于子进程结束,子进程于是成为进程1(init进程)的子进程,直到关机才会回收!

  • 相关阅读:
    《Eclipse中的一些快捷键》
    《Java中的抽象类及抽象类的作用》
    《Java中的不可变类》
    《final修饰基本类型变量和引用类型变量的区别》
    《类成员案例》
    《Java中的单例模式--两种》
    《Java中的自动装箱和拆箱功能.》
    Chrome 经典插件
    Sublimeの虚拟环境(Venv)设置
    HTTP下午茶
  • 原文地址:https://www.cnblogs.com/xiaobaizzz/p/12398484.html
Copyright © 2020-2023  润新知