首先来看一段从《UNIX环境高级编程》中摘录的一段很有意思的代码。借此我们再来谈谈fork()函数的一些问题。

#include "apue.h"

static void charatatime(char*);

int
main(void)
{
pid_t pid; if((pid=fork())<0){
err_sys("fork error");
}else if(pid==0){
charatatime("output from child\n");
}else{
charatatime("output from parent\n");
}
exit(0);
} static void
charatatime(char *str)
{
char *ptr;
int c; setbuf(stdout,NULL); /*set unbuffered*/
for(ptr=str;(c=*ptr++)!=0;)
putc(c,stdout);
}

这段代码究竟干了些啥呢?事实上很easy,首先用fork()函数生成了一个子进程。

事实上子进程能够看成是父进程的一个复制。

那么在如上的一段代码中,怎么推断是子进程还是父进程在运行呢?这时候我们就要来看看fork()函数的返回值了。

fork()的返回值:

当fork被调用之后,父子进程都从fork()之后開始执行。当然,父子进程要干的事情是不一样的,可是前面说了,子进程就是父进程的一个复制。它们事实上是共享一个代码段的。

这个时候,我们就要依靠fork()的返回值来推断当前执行的程序是父进程还是子进程了。fork()函数是个很有意思的家伙。它仅仅被调用了一次,可是却有两个返回值,分别返回到父子进程中。

在父进程中,fork()返回的是子进程的进程ID。值得注意的是,仅仅有在fork()函数的时候。父进程才干得到子进程的ID。否则的话就没有机会了。由于一个父进程能够有多个子进程。想要通过一个函数,得到某个确切的子进程的进程ID显然是比較困难的。

与父进程不同的是。子进程通常仅仅有一个父进程。因此能够通过一个叫getppid()的函数,找到自己父进程的ID。

而fork()在子进程中的返回值是0.这又是为什么呢?由于0一般是系统保留的进程号,因此不可能出现子进程的进程号为0的情况。正如上面的代码显示的那样,当pid==0的时候传递给子函数的字符数是“output from child”,否则那就是在父进程中。传递的字符串自然也成了“output from parent”。

接下来另一个问题,那就是,当fork()之后。父子进程事实上能够看成是两个独立的进程了。

那究竟是先运行父进程呢?还是先运行子进程呢?因此我们接着来谈谈进程间的竞争问题。

进程间的竞争(race condition):

那父子进程究竟是谁先执行呢?事实上一般来说,这是无法预測的,这要看内核的调度算法等一系列其它的因素。

我们能够会过来看看上面的代码。在父子进程共同调用的charatatime函数中,我们首先用setbuf取消了标准I/O的缓冲。这样在以下的for循环中,仅仅要putc一次,就会有对应的字符显示在shell上。依据上面的分析,我们能够预測的是,两个字符串可能并不会依照先后顺序完整地输出。由于进程间非常可能进行切换,一个字符串可能还没输完。内核就转而执行还有一个字符串的输出了。因此显示的shell中显示的结果非常可能是交叉输出的字符串。以下的图就为我们展示了结果:

非常显然。输出的结果是不可预測的,有时候是比較规则的输出,但有些时候就凌乱了。而这,就是进程间的竞争(race condition)。当然,解决竞争的方法有非常多。我们能够通过信号(signal)以及进程间通信(IPC)等待方式。来解决竞争的问题。这些就放到以后再说啦!

參考文献:《Advanced Programming in the UNIX Environment》

从一段代码看fork()函数及其引发的竞争的更多相关文章

  1. 一段代码看 Java 引用类型

    Java 中的操作数(不知道叫什么,相对于 bytecode 而言,类似 CPU 的操作码和操作数)分为值类型和引用类型: 值类型就是直接存储最终数值的,如 char, int, float, dou ...

  2. 127个常用的JS代码片段,每段代码花30秒就能看懂(上)

    127个常用的JS代码片段,每段代码花30秒就能看懂(上) JavaScript 是目前最流行的编程语言之一,正如大多数人所说:“如果你想学一门编程语言,请学JavaScript.” FreeCode ...

  3. Linux多任务编程之二:fork()函数及其基础实验(转)

    来源:CSDN  作者:王文松 转自Linux公社 fork()函数 在 Linux 中创建一个新进程的唯一方法是使用fork()函数.fork()函数是 Linux 系统中一个非常重要的函数,和咱们 ...

  4. Linux环境fork()函数详解

    Linux环境fork()函数详解 引言 先来看一段代码吧, 1 #include <sys/types.h> 2 #include <unistd.h> 3 #include ...

  5. 知识点查缺补漏贴02:Linux环境fork()函数详解

    引言 先来看一段代码吧, #include <sys/types.h> #include <unistd.h> #include <stdio.h> #includ ...

  6. fork 函数的一点学习

    昨天某位少年问了我一个问题,#include<stdio.h> int main() { fork(); fork(); fork(); printf("hello " ...

  7. fork函数详解(附代码)

    虽然篇幅很长,但大多是易懂的代码,不用担心看不完 这里的所有操作,都将在下面的代码中有所体现 fork会拷贝当前进程的内存,并创建一个新的进程.如上图,fork函数会将整个进程的内存镜像拷贝到新的内存 ...

  8. 从linux0.11中起动部分代码看汇编调用c语言函数

    上一篇分析了c语言的函数调用栈情况,知道了c语言的函数调用机制后,我们来看一下,linux0.11中起动部分的代码是如何从汇编跳入c语言函数的.在LINUX 0.11中的head.s文件中会看到如下一 ...

  9. js中闭包来实现bind函数的一段代码的分析

    今天研究了一下bind函数,发现apply和call还可以有这样的妙用,顺便巩固复习了闭包. var first_object = { num: 42 }; var second_object = { ...

随机推荐

  1. Linux下Samba的配置

    前言: 为了实现windows 和 Linux以及其它操作系统之间的资源共享,软件商推出nfs 和samba两种解决方案.因为市场上缺乏象pc-nfs那样的client工具,使得Linux和windo ...

  2. Linux 编译安装 apache 2.4

    在安装apache之前需要准备一些必要的依赖包 gcc安装: #yum install -y gcc gcc-c++安装: #yum install gcc-c++  apr安装: 下载包:apr-1 ...

  3. android——仿微拍贷滑动圆形菜单

    一次偶然机会接触到微拍贷的app,瞬间被其圆形可滑动菜单吸引了.一直琢磨着给弄出来. 现在弄出来了.先看看效果吧 如果你也喜欢这个菜单.去我的github找源码吧.太忙了.没时间贴代码和讲解了. ht ...

  4. 我跟着siki学Unity3D游戏开发——PongGame

    一.屏幕坐标转换为世界坐标. 1.游戏逻辑,根据界面布局,将墙体控制到对应的位置: vector3 position=Camer.main.ScreenToWorldPoint(new vetor2( ...

  5. java菜鸟篇<一> 对JsonObject 和JsonArray知识点理解

    今天遇到从前台拿值(json数组格式),从request里边取值,然后经过一系列的处理方式,在用request返回去 1.先把request里的值赋值给String string类型的变量 2.因为前 ...

  6. (转)Ubuntu中让终端对于历史输出的内容保持足够长

    原地址:http://www.crifan.com/ubuntu_terminal_make_retain_long_enough_history_output_content/ Ubuntu下用终端 ...

  7. html验证码

    一.原理 1.在webservice服务端,新建一个Bitmap对象,将验证码字符串.干扰线和干扰点绘制到此Bitmap上——>转换为字节数组——>Base64字符串 2.<img ...

  8. ActionSupport.getText()方法 以及 js中:<s:text name="" />

    下面略述com.opensymphony.xwork2.ActionSupport.getText()方法 public String getText(String aTextName) 说明:Get ...

  9. BNUOJ flower (搜索)

    春天到了,师大的园丁们又开始忙碌起来了. 京师广场上有一块空地,边界围成了一个多边形,内部被划分成一格一格的.园丁们想在这个多边形内的每一格内种植一些花. 现在请你帮忙计算一下一共最多可以种多少花. ...

  10. c链表结点的删除和添加

    #include<stdio.h> #include<stdlib.h> typedef char datetype;/*定义新的数据类型名*/ typedef struct ...