fork() 函数简介

fork系统调用用于创建一个新进程,称为子进程,它与进行fork()调用的进程(父进程)并发运行。创建新的子进程后,两个进程都将执行fork()系统调用之后的下一条指令。子进程使用相同的PC(程序计数器),相同的CPU寄存器,相同的打开文件,这些文件在父进程中使用。

fork()

它不接受任何参数并返回一个整数值。

下面是fork()返回的不同值。

负值:创建子进程失败。

:返回到新创建的子进程。

正值:返回给父亲或调用者。该值包含新创建子进程的进程ID。

代码

  1. 预测以下程序的运行结果:

    #include <stdio.h>
    #include <sys/types.h>
    #include <unistd.h>
    int main()
    {
    // 在此指令后生成两个运行相同程序的进程
    fork(); printf("Hello world!\n");
    return 0;
    }

    运行结果

    Hello world!
    Hello world!
  2. 计算打印hello的次数。

    #include <stdio.h>
    #include <sys/types.h>
    int main()
    {
    fork();
    fork();
    fork();
    printf("hello\n");
    return 0;
    }

    运行结果

    hello
    hello
    hello
    hello
    hello
    hello
    hello
    hello

    解释

    hello打印的次数等于创建的进程数。进程总数=\(2^n\),其中n是fork系统调用的数量。所以这里\(n=3\),\(2^3=8\)。

    让我们为这三行添加一些标签名称:

    fork ();   // Line 1
    fork (); // Line 2
    fork (); // Line 3 // 一共 7 个子进程,它们中每一个分别创建于这三行中的哪一个呢? L1 // 有 1 个进程创建于Line 1 的fork() P1
    / \
    L2 L2 // 有 2 个进程创建于Line 2 的fork() P2~P3
    / \ / \
    L3 L3 L3 L3 // 有 4 个进程创建于Line 3 的fork() P4~P7

    因此总共有八个进程(新子进程和一个原始进程)。

    如果我们想要将进程之间的关系表示为树形层次结构,它将如下所示:

    主要进程:p0。

    第一个分叉创建的进程:P1。

    第二个分叉创建的进程:P2,P3。

    第三个分叉创建的进程:P4,P5,P6,P7

                P0
    / | \
    P1 P4 P2
    / \ \
    P3 P6 P5
    /
    P7
  3. 预测以下程序的运行结果:

    #include <stdio.h>
    #include <sys/types.h>
    #include <unistd.h>
    void forkexample()
    {
    // 子进程,因为返回值为零
    if (fork() == 0)
    printf("Hello from Child!\n"); // 父进程,因为返回值非零
    else
    printf("Hello from Parent!\n");
    } int main()
    {
    forkexample();
    return 0;
    }

    运行结果

    1.
    Hello from Child!
    Hello from Parent!
    (或者)
    2.
    Hello from Parent!
    Hello from Child!

    解释

    在上面的代码中,创建子进程,fork()在子进程中返回0,向父进程返回正整数。

    在这里,两个输出是都是有可能的,因为父进程和子进程同时运行。所以我们不知道OS首先把控制权交给哪个进程父进程或子进程。

    重要提示:父进程和子进程运行相同的程序,但这并不意味着它们是相同的。OS为这两个进程分配不同的数据和状态,并且控制这些进程的流程也可以不同。请参见下一个示例

  4. 预测以下程序的运行结果:

    #include <stdio.h>
    #include <sys/types.h>
    #include <unistd.h> void forkexample()
    {
    int x = 1; if (fork() == 0)
    printf("Child has x = %d\n", ++x);
    else
    printf("Parent has x = %d\n", --x);
    } int main()
    {
    forkexample();
    return 0;
    }

    运行结果

    Parent has x = 0
    Child has x = 2
    (或者)
    Child has x = 2
    Parent has x = 0

    解释

    这里,一个进程中的全局变量变化不会影响另外两个进程,因为两个进程的数据/状态不同。而且父进程和子进程同时运行,所以可以有两个输出。

fork() vs exec()

fork系统调用创建一个新进程。fork()创建的新进程是当前进程(返回值除外)的副本。exec()系统调用用新程序替换当前进程。

练习:

  1. 一个进程执行以下代码

    for (i = 0; i < n; i++)
    fork();

    创建的子进程总数为:

    (A) n

    (B) 2^n – 1

    (C) 2^n

    (D) 2^(n+1) – 1;

    查看此题答案

  2. 考虑以下代码片段

    if (fork() == 0) {
    a = a + 5;
    printf("%d, %d\n", a, &a);
    } else {
    a = a –5;
    printf("%d, %d\n", a, &a);
    }

    设u,v是父进程打印的值,x,y是子进程打印的值。下列哪一项是正确的?

    (A) u = x + 10 and v = y

    (B) u = x + 10 and v != y

    (C) u + 10 = x and v = y

    (D) u + 10 = x and v != y

    查看此题答案

  3. 预测以下程序的输出

    #include <stdio.h>
    #include <unistd.h>
    int main()
    {
    fork();
    fork() && fork() || fork();
    fork(); printf("forked\n");
    return 0;
    }

    查看此题答案

fork() 函数简介的更多相关文章

  1. linux进程编程:子进程创建及执行函数简介

    linux进程编程:子进程创建及执行函数简介 子进程创建及执行函数有三个: (1)fork();(2)exec();(3)system();    下面分别做详细介绍.(1)fork()    函数定 ...

  2. Linux C 中 fork() 函数详解

    一.fork入门知识 一个进程,包括代码.数据和分配给进程的资源.fork() 函数通过系统调用创建一个与原来进程几乎完全相同的进程,也就是两个进程可以做完全相同的事,但如果初始参数或者传入的变量不同 ...

  3. 进程间通信--fork函数

    #include <unistd.h> pid_t fork(void); fork() creates a new process by duplicating the calling ...

  4. Fork函数初识

    fork函数用于创建子进程,典型的调用一次,返回两次的函数.其中调用进程返回子进程的PID,而子进程则返回0.但是两个进程的执行顺序是不定的. fork函数调用完成以后父进程的虚拟存储空间被拷贝给了子 ...

  5. fork()函数详解

    原文链接:http://blog.csdn.net/jason314/article/details/5640969  一.fork入门知识 一个进程,包括代码.数据和分配给进程的资源.fork()函 ...

  6. Linux Shell系列教程之(十五) Shell函数简介

    本文是Linux Shell系列教程的第(十五)篇,更多Linux Shell教程请看:Linux Shell系列教程 函数可以将一个复杂功能划分成若干模块,从而使程序结构更加清晰,代码重复利用率更高 ...

  7. fork函数

    在Unix/Linux中用fork函数创建一个新的进程.进程是由当前已有进程调用fork函数创建,分叉的进程叫子进程,创建者叫父进程.该函数的特点是调用一次,返回两次,一次是在父进程,一次是在子进程. ...

  8. Linux—fork函数学习笔记

    fork()函数 在赋值语句pid = fork();之前,只有一个进程在执行这段代码,但在这条语句之后,就变成两个进程在执行了,这两个进程的代码部分完全相同.> 两个进程中,原先就存在的那个被 ...

  9. 【液晶模块系列基础视频】4.5.X-GUI图形界面库-进度条等函数简介

    [液晶模块系列基础视频]4.5.X-GUI图形界面库-进度条等函数简介 ============================== 技术论坛:http://www.eeschool.org 博客地址 ...

随机推荐

  1. 膜态沸腾UDF【转载】

    膜态沸腾的UDF,添加注释.其中获取VOF梯度的方法详见前面的日志,其中很多宏无法通过UDF手册查阅, 蒸汽相中的质量源项的一般形式为: 式中: 通过一阶近似,热流之差可表达为: 式中: 通过此近似, ...

  2. DM当中用文本输入点【转载】

    摘自<ANSYS 13.0 Workbench数值模拟技术> 通过XYZ坐标的文本文件创建3D曲线,文本需要满足一定的格式,格式化文本中,#表示此行是注释,忽略空行,数据行包括5个数据域, ...

  3. gitconfig别名配置

    vim ~/.gitconfig 进行配置 [user] name = Your Name email = you@yourdomain.example.com [core] editor = vim ...

  4. 13.mysql数据库

    1.mysql数据库建立           yum install mysql-server           mysql -u root                  mysqladmin ...

  5. MySQL 行转列 -》动态行转列 -》动态行转列带计算

    Pivot Table Using MySQL - A Complete Guide | WebDevZoomhttp://webdevzoom.com/pivot-table-using-mysql ...

  6. AndoridSQLite数据库开发基础教程(8)

    AndoridSQLite数据库开发基础教程(8) 添加索引 索引是一种通过预先排序和对表的一个或多个列构建索引表来优化数据库查找的手段.下面为表添加索引,操作步骤如下: (1)在打开的数据库中,单击 ...

  7. 如何解决Access操作或事件已被禁用模式阻止

    操作或事件已被禁用模式阻止.本来是Access安全设置的一部分,可以防止一些危险性的宏自动运行损坏数据,但是如果是自己在设计或是修改Access数据库的时候,这个就比较烦人了,一次次的提示,每次都需要 ...

  8. log4j 异常时在日志文件里面显示空的。

    如下图所示,输入的时候不要写 e.getStackTrace() 一般情况下不会出问题,但有时候就会出问题 解决方案

  9. window TOMCAT 端口被占用了怎么办?

    查看80端口被哪些程序占用了 netstat -ano|findstr "80" 根据pid(进程id) 查询对应的应用程序 tasklist|findstr "1828 ...

  10. Qt编写气体安全管理系统10-数据导出

    一.前言 数据导出一般指导出到excel表格,可能有部分用户还需要导出到pdf,因为pdf基本上不可编辑,防止用户重新编辑导出的数据,excel可能绝大部分用过电脑的人都知道,广为流行,主要就是微软的 ...