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.

  • 相关阅读:
    idea设置全局ignore
    win 2012 安装mysql 5.7.20 及报错 This application requires Visual Studio 2013 Redistributable. Please ins
    win 2012 安装mysql 5.7.20 及报错 This application requires Visual Studio 2013 Redistr
    kafka 删除 topic
    java编译中出现了Exception in thread “main" java.lang.UnsupportedClassVersionError
    Centos中使用yum安装java时,没有jps的问题的解决
    Spring 整合Junit
    Spring纯注解配置
    Spring 基于注解的 IOC 配置
    打印java系统的信息
  • 原文地址:https://www.cnblogs.com/fenglongyu/p/7624440.html
Copyright © 2011-2022 走看看