zoukankan      html  css  js  c++  java
  • 从一段代码看fork()函数及其引发的竞争

     首先来看一段从《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
    ");
      }else{
        charatatime("output from parent
    ");
      }
      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》

      

  • 相关阅读:
    获取url中的参数
    css 实现单行以及多行文本溢出显示省略号
    页面跳转不带 referrer的方法
    iframe加载完成事件
    es6模块化规则(一)
    kindle电子书下载网站收藏
    vue多页面项目配置
    使用原生ajax及其简单封装
    在vue中使用jq或者第三方插件
    写博客常用语法
  • 原文地址:https://www.cnblogs.com/blfshiye/p/5165593.html
Copyright © 2011-2022 走看看