【问题标题】:fork order of execution分叉执行顺序
【发布时间】:2011-07-09 01:36:31
【问题描述】:
main()
{
if(!fork())
 while(1)
  printf("HELLO");
else
 while(1)
  printf("WORLD");

}

输出:... HELLO HELLO HELLO ....等等, 但是执行应该是 "RANDOM" 因为分叉和父进程是不同步的 我必须得到 HELLO WORLD WORLD HELLO WORLD ...(我所期望的随机顺序) 但这并没有发生。 谁能解释一下。

【问题讨论】:

标签: c linux posix scheduling fork


【解决方案1】:

stdio 是缓冲的,所以在缓冲区被填满之前,两个进程都不会写入任何内容,然后会将整个写入作为一个单元(对于普通文件通常是原子的,但对于终端设备不一定是原子的,以及它是否是原子的)对于管道是一件复杂的事情)。此外,如果您在单核机器上,一个进程将持续运行,直到内核认为它已经花费了足够的 cpu 时间,然后另一个进程将被调度,等等。

如果您想解决 stdio 缓冲问题,请在main 的开头添加setbuf(stdout, 0); 或使用stderr(默认情况下无缓冲)。

【讨论】:

    【解决方案2】:

    好的,首先你没有得到 HELLO 和 WORLDs 的完全随机的混合词,因为 stdout 被缓冲了。

    因此,您的父母正在打印 HELLO,直到该缓冲区已满,然后整个缓冲区最终显示在您的屏幕上。孩子也一样。

    如果你想同步这个,你可以使用 2 个管道在你的父母和孩子之间进行通信。 例如

    • 父打印“HELLO”,
    • child 开始从 pipe1 读取。
    • 父母向 pipe1 写入一个字符,表示孩子应该打印“WORLD”
    • parent 开始从 pipe2 读取
    • child 从 pipe1 读取,打印“WORLD”
    • child 向 pipe2 写入一个字符,表示 parent 应该打印“HELLO”
    • 重复上述操作

    -

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    
    void err(const char *error)
    {
        perror(error);
        exit(1);
    }
    
    void run_handler(int readfd,int writefd,const char *message)
    {
        for(;;) {
            char ch;
            int i;
    
            if((i = read(readfd,&ch,1)) == 0)
               break;
            else if(i < 0)
                err("read");
    
            //important: fflush the text so it ends up in the output
            //and not in an internal FILE* buffer.
            if(fputs(message,stdout) == EOF || fflush(stdout) == EOF) 
               break;
    
            if(write(writefd,&ch,1) != 1)
                err("write");
        }
    }
    
    int main()
    {
        int pipe1[2];
        int pipe2[2];
        pid_t pid;
    
        if(pipe(pipe1) != 0)
            err("pipe1");
        if(pipe(pipe2) != 0)
            err("pipe2");
    
        if((pid = fork()) == 0 ) {
            //write one char to the parent to get it started
            char ch = '.';
            if(write(pipe1[1],&ch,1) != 1)
                err("write");
            //close the pipe ends we don't need
            close(pipe1[0]);
            close(pipe2[1]);
    
            run_handler(pipe2[0],pipe1[1],"WORLD\n");
        }else if(pid > 0) {
            //close the pipe ends we don't need
            close(pipe1[1]);
            close(pipe2[0]);
            run_handler(pipe1[0],pipe2[1],"HELLO ");
        } else {
           err("fork");
        }
    
        return 0;
    }
    

    【讨论】:

      【解决方案3】:
      int main()
      {
        if(!fork())
          while(1) {
            printf("HELLO");
            fflush(stdout);
          }
        else
          while(1) {
            printf("WORLD");
            fflush(stdout);
          }
      }
      

      使用这个,printf 的缓冲就不会影响你的结果。

      【讨论】:

      • 如果上下文切换发生在printf("HELLO")fflush(stdout) 之间,甚至没有说
      • 他的测试方法不是很准确:)
      猜你喜欢
      • 2017-02-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-11-23
      • 2018-08-12
      • 2013-11-12
      相关资源
      最近更新 更多