• linux c编程:进程控制(二)_竞争条件


     

    前面介绍了父子进程,如果当多个进程企图对共享数据进行处理。而最后的结果又取决于进程运行的顺序时,就认为发生了竞争关系。通过下面的例子来看下

    在这里标准输出被设置为不带缓冲的,于是父子进程每输出一个字符就要进行一次write调用。这样做的目的是尽可能多次地在两个进程之间进行切换,以便演示竞争条件。

    static void charatatime(char *str){

        char *ptr;

        int c;

        setbuf(stdout,NULL);

        for(ptr=str;(c=*ptr++)!=’‘;)

            putc(c,stdout);

    }

    void competition(){

        pid_t pid;

        if ((pid=fork()) < 0){

            printf("error");

        }

        else if(pid == 0){

            charatatime("output from child ");

        }

        else{

            charatatime("output from parent ");

        }

        exit(0);

    }

    来看下系统运行的结果:

    第一次:

    第二次:

    第三次:

    通过三次运行结果来看,除了第一次运行正常外,其他两次的字符都是杂乱的。原因就在于父子进程启动的顺序是有先有后的。

    为了避免竞争条件,在多个进程之间需要有某种形式的信号发送和接收的方式。在linux中可以使用信号机制。具体实现方法如下

    #include <stdio.h>

    #include <stdlib.h>

    #include <unistd.h>

    #include <sys/wait.h>

    #include <fcntl.h>

    #include <signal.h>

    #include <sys/types.h>

     

    static volatile sig_atomic_t sigflag;

    static sigset_t newmask, oldmask, zeromask;

    /* signal handler for SIGUSR1 and SIGUSR2 */

    static void sig_usr(int signo)

    {

     sigflag = 1;

     return;

    }

    void TELL_WAIT()

    {

     if(signal(SIGUSR1, sig_usr) == SIG_ERR)

      printf("signal SIGUSR1 error ");

     if(signal(SIGUSR2, sig_usr) == SIG_ERR)

      printf("signal SIGUSR2 error ");

     

     sigemptyset(&zeromask);

     

     sigemptyset(&newmask);

     sigaddset(&newmask, SIGUSR1);

     sigaddset(&newmask, SIGUSR2);

     

     /* block SIGUSR1 and SIGUSR2, and save current signal mask */

     if(sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0)

      printf("SIG_BLOCK error ");

    }

    void TELL_PARENT(pid_t pid)

    {

     kill(pid, SIGUSR2); /* tell parent we are done */

    }

    void WAIT_PARENT()

    {

     while(sigflag == 0)

      sigsuspend(&zeromask); /* wait for parent */

     

     sigflag = 0;

     

     /* reset signal mask */

     if(sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0)

      printf("SIG_SETMASK error ");

    }

    void TELL_CHILD(pid_t pid)

    {

     kill(pid, SIGUSR1);

    }

    void WAIT_CHILD()

    {

     while(sigflag == 0)

      sigsuspend(&zeromask); /* wait for parent */

     

     sigflag = 0;

     

     /* reset signal mask */

     if(sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0)

      printf("SIG_SETMASK error ");

    }

    void do_task(char *task_str)

    {

     printf("%s ", task_str);

    }

    那么在之前的代码更新如下:

    oid competition(){

        pid_t pid;

        TELL_WAIT();

        if ((pid=fork()) < 0){

            printf("error");

        }

        else if(pid == 0){

            WAIT_PARENT();  //等待父进程先进行

            charatatime("output from child ");

        }

        else{

            charatatime("output from parent ");

            TELL_CHILD(pid); //告诉子进程运行

        }

        exit(0);

    }

    此时运行的顺序就会固定。也不会出现杂乱的字符。

  • 相关阅读:
    NFC Basics(基本NFC)——翻译自developer.android.com
    【LeetCode】Sort Colors 解题报告
    发送手机物理标识请求
    Java编程介绍
    emacs 中使用git diff命令行
    OpenJudge百炼习题解答(C++)--题4074:积水量
    编程之美2.9 斐波那契数列
    Application Architecture Determines Application Performance
    程序包javax.servlet.annotation不存在
    mysql 严格模式 Strict Mode说明
  • 原文地址:https://www.cnblogs.com/zhanghongfeng/p/9038387.html
Copyright © 2020-2023  润新知