zoukankan      html  css  js  c++  java
  • fork和缓冲区

      fork在面试中经常被问到,在这里复习一下。

      frok创建子进程,父子进程共享.text段,子进程获得父进程数据段、堆和栈的副本,由于在fork之后经常跟随者exec,所以很多实现并不执行父进程数据段、堆和栈的完全复制,而是使用写时复制(Copy-On-Write,COW)技术。这些区域由父子进程共享,并被内核设为只读,如果父子进程试图修改这些区域,则内核只为修改区域的那块内存制作一个副本。

    接下来的程序演示一下fork函数的功能

    #include<unistd.h>
    #include<stdio.h>
    #include<stdlib.h>
    #include<sys/types.h>
    
    void err_sys(const char *s)
    {
        printf("error:%s",s);
        exit(EXIT_FAILURE);
    }
    
    int glob = 6;
    char buf[] = "a write to stdout
    ";
    
    int main()
    {
        int var;
        pid_t pid;
    
        var = 88;
        if(write(STDOUT_FILENO,buf,sizeof(buf)-1) != sizeof(buf)-1)
            err_sys("write error");
        printf("before fork
    ");
        if((pid = fork())<0)
            err_sys("fork error");
        else if(pid == 0)
        {
            glob++;
            var++;
        }
        else
            sleep(2);
        printf("pid = %d,glob = %d,var = %d
    ",getpid(),glob,var);
        exit(0);
    }

     编译得到fork_sample,运行结果如下:

    当直接执行fork_sample时,结果不出乎意料。在fork前先打印"before fork ",fork之后父子进程分别打印。

    但是当程序输出重定向到temp文件时(即./fork_sample > temp的作用),读取temp文件(即cat temp),我们发现"before fork "被输出了两遍,这是为什么呢?

    这得从标准I/O库的缓冲说起。

    标准I/O库提供了三种类型的缓冲:

    (1) 全缓冲:填满标准I/O缓冲区才实际进行I/O操作。

    (2)行缓冲:在输入和输出中遇到换行符时,标准I/O库执行I/O操作,当流涉及终端时,通常使用行缓冲。

    (3)不带缓冲:标准出错流stderr通常是不带缓冲的。

    上面说的缓冲指的是应用层的缓冲,在进行实际的I/O操作时,相关的系统调用(read和write)其实在内核也有缓冲区的。

    当直接执行./fork_sample时,由于标准输出时行缓冲的,所以遇到换行符' '后缓冲区被冲洗。

    当将程序输出重定向到别的文件时,是标准输出是全缓冲的,fork之前printf的数据仍在缓冲区中,在fork时该缓冲区也被复制到子进程中,因此我们就会看到"before fork "输出了两次。

  • 相关阅读:
    c# 读改xml
    window
    c# 日期字符格式化
    验证字符串是否为数字
    MySQL常用操作基本操作
    将参数扩展为指定长度的字符串,不足位数的在前方加0
    hp服务器重装后,启动apache和tomcat和mysql
    [转] 各种取整数函数(VB)
    [原] access97中textbox类似vb的maxlength功能的实现
    [转] csv文件的读写
  • 原文地址:https://www.cnblogs.com/tonychen-tobeTopCoder/p/5335452.html
Copyright © 2011-2022 走看看