设为首页 加入收藏

TOP

重定向对标准IO缓冲的影响
2015-07-20 17:42:50 来源: 作者: 【 】 浏览:1
Tags:定向 标准 缓冲 影响

今天在看APUE3进程章节的fork函数的时候,有一个例程中使用了标准IO函数(printf),在输出到终端的时候只输出一次,但重定向到某个文件时,却由于子进程的关系输出了两次。具体代码如下:

#include "apue.h"

int globvar = 6; /* external variable in initialized data */
char buf[] = "a write to stdout\n";

int  main(void) 
{
        int var; /* automatic variable on the stack */
        pid_t pid;

        var = 88;
        if (write(STDOUT_FILENO, buf, sizeof(buf)-1) != sizeof(buf)-1)
                err_sys("write error");
        printf("before fork\n"); /* we don't flush stdout */

        if ((pid = fork()) < 0) {
                err_sys("fork error");
        } else if (pid == 0) { /* child */
                globvar++; /* modify variables */
                var++;
        } else {
                sleep(2); /* parent */
        }

        printf("pid = %ld, glob = %d, var = %d\n", (long)getpid(), globvar, var); 
        exit(0);
} 

输出如下:

sahpah:~/apue.3e/proc$ ./fork1
a write to stdout
before fork
pid = 14761, glob = 7, var = 89
pid = 14760, glob = 6, var = 88
sahpah:~/apue.3e/proc$ ./fork1 > h
sahpah:~/apue.3e/proc$ cat h
a write to stdout
before fork
pid = 15649, glob = 7, var = 89
before fork
pid = 15648, glob = 6, var = 88


这是由于在 Linux下,默认符合如下缓冲特征: 当且仅当标准输入和标准输出并不指向交互式设备时,它们才是全缓冲的。标准错误决不会是全缓冲的。
因此,在标准输出直接输出到终端时,它是行缓冲的,由换行符冲洗。 所以,在fork之前第一个个printf函数由换行符将缓冲区冲洗完,仅打印一次“before fork”。
 printf("before fork\n"); 

当使用“./fork1 > h”重定向到h文件时,使用的是全缓冲,fork前的printf缓冲区中的数据并不会被冲洗,而fork出来的子进程获得了父进程数据空间、堆和栈的副本,所以子进程也继承了父进程缓冲区中的数据,即父进程和子进程都有了该行的缓冲区,随后第二个printf将数据追加到该缓冲区中,exit函数在退出前将各自的缓冲区进行冲洗,于是打印了两次“before fork”。
修改方法: 1.在第一个printf后使用fflush函数强制对标准输出流进行冲洗:
#include "apue.h"

int globvar = 6; /* external variable in initialized data */
char buf[] = "a write to stdout\n";

int  main(void) 
{
        int var; /* automatic variable on the stack */
        pid_t pid;

        var = 88;
        if (write(STDOUT_FILENO, buf, sizeof(buf)-1) != sizeof(buf)-1)
                err_sys("write error");
        printf("before fork\n"); /* we don't flush stdout */
        fflush(stdout); //force flush

        if ((pid = fork()) < 0) {
                err_sys("fork error");
        } else if (pid == 0) { /* child */
                globvar++; /* modify variables */
                var++;
        } else {
                sleep(2); /* parent */
        }

        printf("pid = %ld, glob = %d, var = %d\n", (long)getpid(), globvar, var); 
        exit(0);
} 

进行强制冲洗后输出如下:
sahpah:~/apue.3e/proc$ ./fork1
a write to stdout
before fork
pid = 14761, glob = 7, var = 89
pid = 14760, glob = 6, var = 88
sahpah:~/apue.3e/proc$ ./fork1 > h
sahpah:~/apue.3e/proc$ cat h
a write to stdout
before fork
pid = 15649, glob = 7, var = 89
pid = 15648, glob = 6, var = 88

2.使用setvbuf设置标准输出流的缓冲类型:

#include "apue.h"

int globvar = 6; /* external variable in initialized data */
char buf[] = "a write to stdout\n";

int  main(void) 
{
        int var; /* automatic variable on the stack */
        pid_t pid;

        var = 88;

        setvbuf(stdout, NULL, _IOLBF, 0);//set buffer

        if (write(STDOUT_FILENO, buf, sizeof(buf)-1) != sizeof(buf)-1)
                err_sys("write error");
        printf("before fork\n"); /* we don't flush stdout */

        if ((pid = fork()) < 0) {
                err_sys("fork error");
        } else if (pid == 0) { /* child */
                globvar++; /* modify variables */
                var++;
        } else {
                sleep(2); /* parent */
        }

        printf("pid = %ld, glob = %d, var = %d\n", (long)getpid(), globvar, var); 
        exit(0);
} 

setvbuf将stdout流类型重设置为行缓冲,但其缓冲区由我们指定,此处指向NULL,则标准IO库自动为该流分配适当长度的缓冲区。当数据超过缓冲区长度时,缓冲区则被冲洗,而此处缓冲区长度设置为0,故每个接收的数据都立即被冲洗。

输出如下: sahpah:~/apue.3e/proc$ ./fork1
a write to stdout
before fork
pid = 43680, glob = 7, var = 89
pid = 43679, glob = 6, var = 88
sahpah:~/apue.3e/proc$ ./fork1 > h
sahpah:~/apue.3e/proc$ cat h
a write to stdout
before fork
pid = 43682, glob = 7, var = 89
pid = 43681, glob = 6, var = 88


】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇NYOJ-众数问题 下一篇ZOJ 3798 Abs Problem

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容:

·工业机器人TCP校准中 (2025-12-25 05:19:17)
·opc 通讯协议与 TCP (2025-12-25 05:19:15)
·labview中tcp/ip通信 (2025-12-25 05:19:13)
·新书介绍《Python数 (2025-12-25 04:49:47)
·怎么利用 Python 进 (2025-12-25 04:49:45)