fork和缓冲区

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

  frok建立子进程,父子进程共享.text段,子进程得到父进程数据段、堆和栈的副本,因为在fork以后常常跟随者exec,因此不少实现并不执行父进程数据段、堆和栈的彻底复制,而是使用写时复制(Copy-On-Write,COW)技术。这些区域由父子进程共享,并被内核设为只读,若是父子进程试图修改这些区域,则内核只为修改区域的那块内存制做一个副本。函数

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

#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\n";

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\n");
    if((pid = fork())<0)
        err_sys("fork error");
    else if(pid == 0)
    {
        glob++;
        var++;
    }
    else
        sleep(2);
    printf("pid = %d,glob = %d,var = %d\n",getpid(),glob,var);
    exit(0);
}

 编译获得fork_sample,运行结果以下:.net

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

可是当程序输出重定向到temp文件时(即./fork_sample > temp的做用),读取temp文件(即cat temp),咱们发现"before fork\n"被输出了两遍,这是为何呢?code

这得从标准I/O库的缓冲提及。blog

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

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

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

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

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

当直接执行./fork_sample时,因为标准输出时行缓冲的,因此遇到换行符'\n'后缓冲区被冲洗。

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

相关文章
相关标签/搜索