曲径通幽论坛

 找回密码
 立即注册
搜索
查看: 8968|回复: 0
打印 上一主题 下一主题

行缓冲与全缓冲

[复制链接]

4918

主题

5880

帖子

3万

积分

GROAD

曲径通幽,安觅芳踪。

Rank: 6Rank: 6

积分
34395
跳转到指定楼层
楼主
发表于 2011-5-27 15:06:07 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
一般标准I/O 库函数带有缓冲机制,如 printf() 函数。

当标准输出连接到终端设备时,它是行缓冲的。也就是说,输出是一行一行的来,每一行由换行符进行冲洗缓冲,相当于输出一行后缓冲区就再没内容。

当标准输出重定向到一个文件时,它是全缓冲的,也就是说缓冲区中的内容虽然输出了,但是在缓冲区中的内容仍然保留,没有被冲洗掉。

下面是示例代码:
[C++] 纯文本查看 复制代码
#include <stdio.h>
#include <stdlib.h>
void pr_stdio(const char *, FILE *);
int main(void)
{
        FILE *fp;
        fputs ("enter any character\n", stdout);
        if (getchar() == EOF) {
                perror("getchar");
                exit (EXIT_FAILURE);
        }
        fputs("one line to standard error\n", stderr);
        pr_stdio("stdin", stdin);
        pr_stdio("stdout", stdout);
        pr_stdio("stderr", stderr);
        if ((fp = fopen("/etc/issue", "r")) == NULL) {
                perror("fopen");
                exit (EXIT_FAILURE);
        }
        if (getc(fp) == EOF) {
                perror("getc");
                exit (EXIT_FAILURE);
        }
        pr_stdio("/etc/issue", fp);
        return (0);
}
void pr_stdio (const char *name, FILE *fp)
{
        printf ("stream = %s, ", name);
        if (fp->_IO_file_flags & _IO_UNBUFFERED)
                printf("unbuffered");
        else if (fp->_IO_file_flags & _IO_LINE_BUF)
                printf("line buffered");
        else
                printf("fully bufferd");
        printf(", buffer size = %d\n", fp->_IO_buf_end - fp->_IO_buf_base);
}

直接在终端上输出:

[root@centos C]# ./buffer
enter any character
one line to standard error
stream = stdin, line buffered, buffer size = 4096
stream = stdout, line buffered, buffer size = 4096
stream = stderr, unbuffered, buffer size = 1
stream = /etc/issue, fully bufferd, buffer size = 4096
进行文件重定向输出:
[root@centos C]# cat std.out
enter any character
stream = stdin, fully bufferd, buffer size = 4096
stream = stdout, fully bufferd, buffer size = 4096
stream = stderr, unbuffered, buffer size = 1
stream = /etc/issue, fully bufferd, buffer size = 4096
第 1 次使三个标准流(stdin, stdout, stderr)与终端相连,第 2 次使它们重定向到文件。

在程序中,_IO_LINE_BUFFERED、_IO_buf_base、_IO_buf_end、_IO_UNBUFFERED 及 _IO_file_flags 在 libio.h 头文件中有定义,这个头文件在 stdio.h 中有包含。

从输出可以看到,标准错误 stderr 是非缓冲的。当标准输入,标准输出,标准错误与终端连接时,它们是行缓冲的,行缓冲的长度是 4096 (在老的内核上可能是1024)。需要注意的是,这并不是将标准输入和标准输出的行限制为 4096 个字节,这只是缓冲区的长度,如果将一个具有 8192 个字节的行输出,那么需要进行两次 write() 系统调用。

当将标准输入和标准输出流重定向到扑通文件时,它们就变成了全缓冲,它的长度也是 4096 个字节。普通文件在系统默认情况下都是全缓冲的。

从下面代码可以比较出行缓冲和全缓冲的区别:
[C++] 纯文本查看 复制代码
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
int     glob = 6;
char    buf[] = "a write to stdout\n";
int main(void)
{
        int     var;
        pid_t   pid;
        var = 88;
        if (write(STDOUT_FILENO, buf, sizeof(buf)-1) != sizeof(buf) - 1) {
                perror ("write");
                exit (EXIT_FAILURE);
        }
        printf ("before fork\n");
        if ((pid = fork()) < 0) {
                perror ("fork");
                exit (EXIT_FAILURE);
        } else if (pid == 0) {
                glob++;
                var++;
        } else {
                sleep(2);
        }
        printf ("pid = %d, glob = %d, var = %d\n", getpid(), glob, var);
        exit(0);
}

也分为两次运行,第 1 次就在终端中直接运行,第 2 次仍然是重定向到文件中。

终端方式:
[beyes@localhost syscall]$ ./fork
a write to stdout
before fork
pid = 2051, glob = 7, var = 89
pid = 2050, glob = 6, var = 88
因为是行缓冲,所以只打印 1 次 "before fork" 。

重定向到文件的输出:
[beyes@localhost syscall]$ ./fork > temp.out
[beyes@localhost syscall]$ cat temp.out
a write to stdout
before fork
pid = 2062, glob = 7, var = 89
before fork
pid = 2061, glob = 6, var = 88

从第 2 次输出中看到有两次 before fork 的打印。第 1 个 "before fork" 是父进程所打印。如上面说的,重定向到文件是全缓冲的方式,所以在这一行内容仍保存在父进程的缓冲区中。接着,在 fork() 出子进程时,子进程要将父进程的数据空间复制到它自己的空间去,这时父进程的缓冲区也理所当然的被子进程复制。于是,父子进程都各自有了该行内容(before fork)的标准 I/O 缓冲区。这样一来,在子进程返回(return)之前子进程里所保存的 "before fork" 也就随之被冲出来。在每个进程终止时,最终会冲洗其缓冲区中的副本。
从:
pid = 2062, glob = 7, var = 89
before fork
这个输出顺序我们可以推断,缓冲区进行数据的缓冲也如同压栈出栈,后来的内容会在缓冲区头部。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|曲径通幽 ( 琼ICP备11001422号-1|公安备案:46900502000207 )

GMT+8, 2025-5-2 23:39 , Processed in 0.063832 second(s), 23 queries .

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表