从一个fork()实例理解全缓冲与行缓冲

本文通过一个具体的C程序示例,深入探讨了无缓冲、行缓冲及全缓冲的区别,特别是在fork()前后对输出的影响,揭示了标准I/O库的缓冲机制如何工作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

转载于:https://www.2cto.com/kf/201511/450212.html

       之前一直对无缓冲、行缓冲、全缓冲不太感冒,然后最近在《UNIX环境高级编程》上看到这样一个例子,感觉挺好的拿来给没看过的小伙伴们看看:

#include <unistd.h>
#include <stdio.h>
 
int globvar = 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);
    printf(before fork
);
    if ((pid = fork()) < 0)
        ;
    else if (pid == 0) {
        globvar++;
        var++;
    } else {
        sleep(2);
    }
 
    printf(pid = %ld, glob = %d, var = %d
, (long)getpid(), globvar, var);
    exit(0);
}

          为了不干扰代码中的几个打印语句我去掉了函数出错返回的处理语句,程序意思也很明确,先使用不带缓冲的系统调用write()将buf写入stdout,然后再打印一行“before fork”,最后fork一个子进程自增变量并打印,父进程休眠2s后打印, 直接运行输出像是这样:

                 

 

好像蛮正常,但如果把输出重定向到一个文件,结果不一样了:

                

明明只有一行的 printf(before fork ) 却被打印了两次。

 

       首先,我们知道write()这种系统调用是无缓冲的,而标准I/O库提供了缓冲机制以尽可能减少使用read和write调用的次数:当流涉及一个终端时(不包含标准错误流),通常使用行缓冲;否则,默认为全缓冲。那么原因很明了了,第一次 ./a.out 输出到终端,默认为行缓冲,字符串“before fork” 由于之后的 被立刻输出了。而 ./a.out > temp.out 输出端重定向到文件时,默认为全缓冲模式,printf(before fork ) 后字符串“before fork ”依然留在缓冲区等待输出(缓冲区溢出或程序退出),而I/O缓冲区是用malloc分配在进程的堆区的。

        fork()执行后子进程获得了父进程数据空间、堆和栈的副本,当然也获得了缓冲区的一个副本;进程结束时,父进程与子进程的缓冲区数据先后被写到了temp.out中,得到两个“before fork”

 

验证一下,我们把 printf(before fork ) 里面的 改成.,输出到标准输出:./a.out 看看:

                 

 

由于没有了换行符,在行缓冲模式下,“before fork.”也被留在了缓冲区里,然后同上面一样被输出了两次。当然我们也可以使用 setbuf 和 setvbuf 修改标准I/O的默认缓冲模式。 另外从该代码可以看出,在fork()之前打开的文件描述符是被父进程与子进程共享的,当然还有该文件的偏移量。        

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值