zoukankan      html  css  js  c++  java
  • 进程控制之竞争条件

    当多个进程都企图对共享数据进行某种处理,而最后的结果又取决于进程运行的顺序时,则我们认为这发生了竞争条件(race condition)。如果在fork之后的某种逻辑显式或隐式地依赖于在fork之后是父进程先运行还是子进程先运行,那么fork函数就会是竞争条件活跃的滋生地。通常,我们不能预料哪一个进程先运行。即使知道哪一个进程先运行,那么在该进程开始运行后,所发生的事情也依赖于系统负载以及内核的调度算法。

    如果一个进程希望等待一个子进程终止,则它必须调用一种wait函数。如果一个进程要等待其父进程终止,则可使用下列形式的循环:

    while ( getppid() != 1 )
        sleep( 1 );

    这种形式的循环(称为轮询(polling))的问题是它浪费了CPU时间,因为调用者每隔1秒都被唤醒,然后再进行条件测试。

    为了避免竞争条件和轮询,在多个进程之间需要有某种形式的信号发送和接收的方法。在UNIX中可以使用信号机制。也可使用各种形式的进程间通信(IPC)。

    在父、子进程的关系中,常常出现下述情况:在调用fork之后,父、子进程都有一些事情要做。假如,要求每个进程在执行完它的一套初始化操作后要通知对方,并且在继续运行之前,要等待另一方完成其初始化操作。这种方案可以用代码描述如下:

    #include "apue.h"
    
    TELL_WAIT();    /* set things up for TELL_xxx & WAIT_xxx */
    
    if ((pid = fork()) < 0)
    {
        err_sys("fork error");
    }
    else if (pid == 0)    /* child */
    {
        /* child does whatever is necessary ... */
    
        TELL_PARENT( getppid() );    /* tell parent we're done */
        WAIT_PARENT();               /* and wait for parent */
    
        /* and the child continue on its way ... */
        exit( 0 );
    }
    
    /* parent does whatever is necessary ... */
    
    TELL_CHILD( pid );        /* tell child we're done */
    WAIT_CHILD();             /* and wait for child */
    
    /* and the parent continues on its way ... */
    
    exit( 0 );

    假定在头文件apue.h中定义了各个需要使用的变量。5个例程TELL_WAIT、TELL_PARENT、TELL_CHILD、WAIT_PARENT以及WAIT_CHILD可以是宏,也可以是函数。(TELL、WAIT的实现方法http://www.cnblogs.com/nufangrensheng/p/3516427.html)

    程序清单8-6输出两个字符串:一个由子进程输出,另一个由父进程输出。因为输出依赖于内核使这两个进程运行的顺序及每个进程运行的时间长度,所以该程序包含了一个竞争条件。

    程序8-6 具有竞争条件的程序

    [root@localhost apue]# cat prog8-6.c
    #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 );
    }

    在程序中将标准输出设置为不带缓冲的,于是每个字符输出到需调用一次write。本例的目的是使内核尽可能地在两个进程之间进行多次切换,以便演示竞争条件。

    [root@localhost apue]# ./prog8-6
    output from poutput from child
    arent
    [root@localhost apue]# ./prog8-6
    output from child
    output from parent

    修改程序清单8-6,以使用TELL和WAIT函数,于是形成了程序清单8-7.行首标以+号的行是新增的行。

    程序清单8-7 修改程序清单8-6以避免竞争条件

    #include "apue.h"
    
    static void charatatime(char *);
    
    int
    main(void)
    {
            pid_t   pid;
    
    +      TELL_WAIT();
    +
            if((pid = fork()) < 0)
            {
                    err_sys("fork error");
            }
            else if(pid == 0)
            {
    +              WAIT_PARENT();    /* parent goes first */
                    charatatime("output from child
    ");
            }
            else
            {
                    charatatime("output from parent
    ");
    +    TELL_CHILD( pid );
            }
            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 );
    }

    运行此程序则能得到所预期的输出;两个进程的输出不再交叉混合。

    程序清单8-7是使父进程先运行。如果将fork之后的行改变成:

    else if(pid == 0)
    {
            charatatime("output from child
    ");
            TELL_PARENT( getppid() );
    }
    else
    {
            WAIT_CHILD();    /* child goes first */
            charatatime("output from parent
    ");
    }

    则子进程先运行。

    本篇博文内容摘自《UNIX环境高级编程》(第二版),仅作个人学习记录所用。关于本书可参考:http://www.apuebook.com/

  • 相关阅读:
    微信小程序里自定义组件,canvas组件没有效果
    微信小程序填坑之路(三):布局适配方案(rpx、px、vw、vh)
    小程序checkbox调整大小
    css让文字竖着排列 writing-mode 属性
    微信小程序 位置定位position详解,相对定位relative,绝对定位absolute相关问题
    小程序国际化实现方式
    mybatis plus 学习
    cesium js学习一加载三维模型【转】
    cesiumjs学习笔记之三——cesium-navigation插件 【转】
    局域网Cesium离线影像及瓦片影像地图加载【转】
  • 原文地址:https://www.cnblogs.com/nufangrensheng/p/3510306.html
Copyright © 2011-2022 走看看