zoukankan      html  css  js  c++  java
  • Linux fork和vfork

    fork 系统调用

    可以通过fork系统调用创建新的进程。调用进程称为父进程,被创建的进程称为子进程。

    fork函数复制当前进程,会在内核进程表中创建一个新的进程表项。新的进程表项有很多属性和原进程相同,如堆指针、栈指针、标志寄存器的值。也有许多属性被赋予新的值,如子进程PPID为原来进程PID。

    原型

    #include <unistd.h>
    
    pid_t fork(void);
    

    fork的特点是:
    1)调用一次,返回2次。
    2次返回区别:子进程返回的是0,父进程返回的是子进程的pid(进程id)。
    原因:一个进程可以有多个子进程,但一个进程却只有一个父进程,并且没有一个函数使得进程可以获得其所有子进程的pid。

    2)子进程和父进程继续执行fork调用之后的指令。

    3)子进程是父进程的副本,子进程获得父进程的数据空间、堆、栈 副本。但子进程和父进程不共享这些存储空间。
    典型的进程存储空间安排如下:

    也就是说,调用fork之后,子进程完全是父进程的副本,进程的存储空间完全一样。不过,由于fork之后经常跟着调用exec,所以很多实现并不执行一个父进程数据段、栈完全一样的副本。

    fork,exec与信号处理函数:fork创建子进程后,子进程具有父进程一样存储空间,信号捕捉函数位于text代码段,在子进程中也是有意义的,子进程会继承父进程的信号处理方式。不过,调用exec后,运行新的程序会覆盖从父进程继承而来的text段,那么信号捕捉函数在新程序中无意义,所以exec会将原先已经设置过的信号捕捉函数重新设置为默认值。

    fork示例程序:
    子进程和父进程同时对变量a自增,然后打印其值

    #include <stdio.h>
    #include <unistd.h>
    #include <stdlib.h>
    
    int main()
    {
        int a = 1;
        pid_t pid;
    
        if ((pid = fork()) == -1) { /* error */
            perror("fork error");
            exit(1);
        }
        else if (pid == 0) { /* child */
            ++a;
            printf("child process a = %d
    ", a);
        }
        else {
            sleep(1);
            ++a;
            printf("parent process a = %d
    ", a);
            wait(pid);
        }
    
        return 0;
    }
    

    运行结果:
    可以看到父子进程变量a是相互独立的

    child process a = 2
    parent process a = 2
    

    vfork 系统调用

    vfork也用来创建新进程。
    原型

    #include <sys/types.h>
    #include <unistd.h>
    
    pid_t vfork(void);
    

    跟fork区别:
    1.调用序列同fork,但语义不同:vfork用于创建一个新进程,但并不将父进程的地址空间完全复制到子进程中,因为子进程会立即调用exec(或exit)。子进程调用exec或exit之前,在父进程的进程空间中运行,也就是说,vfork子进程和父进程共享进程空间。
    如果没有调用exec或exit,直接return返回,可能会带来未知的结果。

    2.vfork保证子进程先运行,调用exec或exit之后,父进程才可能被调度运行。期间,父进程阻塞。fork不能保证父、子进程谁先执行,fork返回后,父子进程都开始并发执行,不存在由于fork导致的阻塞。

    PS:vfork子进程不能return,只能通过exec,再return,或者直接exit。

    vfork示例程序:
    子进程和父进程同时对变量a自增,然后打印其值

    int main()
    {
        int a = 1;
        pid_t pid;
    
        if ((pid = vfork()) == -1) { /* error */
            perror("fork error");
            exit(1);
        }
        else if (pid == 0) { /* child */
            ++a;
            printf("child process a = %d
    ", a);
            exit(1);
        }
        else {
            //sleep(1);
            ++a;
            printf("parent process a = %d
    ", a);
            wait(pid);
        }
    
        return 0;
    }
    

    运行结果:
    可以看到父子进程共享了变量a的值

    child process a = 2
    parent process a = 3
    
  • 相关阅读:
    对于Spring中AOP,DI,IoC概念的理解
    Java多线程(2)线程锁
    JVM中ClassLoader的学习
    用心对待博客,用脚对待cv
    硬核关闭wps for linux的自动备份功能
    [翻译]官网文档,ubuntu使用vscode调试c++
    一文快速入门Shell脚本_了解Shell脚本基本命令
    Ubuntu安装旧版本/指定版本的JDK
    ubuntu1204搭建Andriod4.0环境时了解的相关扩展信息
    避免火狐浏览器产生巨大的磁盘写入量及一些小优化
  • 原文地址:https://www.cnblogs.com/fortunely/p/15042145.html
Copyright © 2011-2022 走看看