zoukankan      html  css  js  c++  java
  • fork()和printf()几点注意细节

    分两点说吧:
    1.fork()函数会把它所在语句以后的语句复制到一个子进程里,单独执行。
    2.如果printf函数最后没有" ",则输出缓冲区不会被立即清空,而fork函数会把输出缓冲区里的内容也都复制到子进程里。
    所以,父进程和子进程各输出2个Hello,共4个。
    如果第一个printf("Hello");写成printf("Hello ");,则只会输出3个Hello,父进程2个,子进程1个。

    缓冲区的问题解答!!

    先来看以下一段代码(test.c):

      1 #include<stdio.h>
      2 #include<sys/types.h>
      3 
      4 int main()
      5 {
      6     pid_t pid;
      7     fprintf(stdout,"%s","Start fork...");
      8     pid = fork();
      9     switch(pid)
     10     {
     11     case -1:
     12         break;
     13     case 0:
     14         printf("%s","Child process. ");
     15         break;
     16     default:
     17         printf("%s","Parent process. ");
     18         break;
     19     }
     20     return 0;
     21 }


    编译执行:

    $gcc -o test test.c
    $./test
    Start fork...Child process.
    Start fork...Parent process.

       出乎意料的是,为什么"Start fork..."输出了两次呢?子进程是从fork之后的语句开始执行的,那么多出来那个"Start fork..."是哪里来的呢?

    先了解一下缓冲区:

      这个缓冲区既不是内核中的缓冲区,也不是用户分配的缓冲区,而是有编译器维护的用户进程空间中的缓冲区.缓冲区类型有:全缓冲(大部分缓冲都是这类型)、行缓冲、无缓冲。

      标准里没有规定各种流是什么缓冲,stderr和stdout是哪种缓冲类型是和环境相关的。 stderr 可能是无缓冲、行缓冲,但不能是全缓冲。stdin 和 stdout 可能是无缓冲、行缓冲,也可能是全缓冲。不过,stdin 和 stdout 如果分别是指键盘和显示器等交互设备(interactive device)的话,那么只能是无缓冲或行缓冲。

      默认情况下,printf()在屏幕输出的时候是行缓冲的,所以父进程在执行了第一个printf语句后,"Start fork..."还保存在缓冲区中,执行fork的时候,父进程缓冲区的数据也被复制到子进程中,子进程在刷新缓冲区的时候,输出了从父进程复制来的"Start fork..."。
     
    下面对程序进行一些修改:
    1、如果把第7句改为:
    fprintf(stdout,"%s","Start fork... ");
    $./test
    Start fork...
    Child process.
    Parent process.
    说明当前环境下printf是行缓冲的。

    把修改过的程序的执行结果重定向到文件中:
    $./test > temp
    $cat temp
    Start fork...
    Child process.
    Start fork...
    Parent process.
    这说明将printf输出结果重定向到文件的时候就变了全缓冲.

    2、如果在第7行以后加入一句:
    fflush(stdout);

    $./test > temp
    $cat temp
    Start fork...
    Child process.
    Parent process.
    我们用fflush强制刷新缓冲区,这样父进程缓冲区被清空。我们在fork之前一般都要用fflush(NULL)清空所有流。

    3、我们把第7句改为:
    fprintf(stderr,"%s","Start fork...");
    $./test > temp
    Start fork...
    $cat temp
    Child process.
    Parent process.

    把修改过的程序的执行结果重定向到文件,把标准错误重定向到标准输出:
    $./test > temp 2>&1
    $cat temp
    Start fork...
    Child process.
    Parent process.
    表明当前环境stderr的默认目标是终端,而且是不缓冲的.

    4、如果我们在第7句之前加入:
    setvbuf(stdout, NULL, _IONBF, 0);
    设置标准输出为无缓冲。
    $./test > temp
    $cat temp
    Start fork...
    Child process.
    Parent process.

  • 相关阅读:
    JavaSE 基础 第17节 流程控制之break、continue、return的用法
    JavaSE 基础 第16节 流程控制之循环结构
    JavaSE 基础 第15节 流程控制之选择结构
    JavaSE 基础 第14节 关系运算符、逻辑运算符与三元运算符
    JavaSE 基础 第13节 算术赋值运算符与自增自减运算符
    MySQL4-SQLAlchemy框架实现
    MySQL3>mysql进阶
    MySQL2>常用命令汇集
    MySQL1>概述
    python-协程
  • 原文地址:https://www.cnblogs.com/fenglongyu/p/7624440.html
Copyright © 2011-2022 走看看