`

UNIX缓冲机制

 
阅读更多

某日一朋友写了一个HELLO WORLD代码,出不来结果,代码如下:

#include <stdio.h>

int  main(int argc, char **argv)

{

    printf("hello world!");

    _Exit(0);

} 

 

 注意到,在代码中printf语句打印的字符串最后没有带换行符,而且最后调用了_Exit函数,这导致了在终端屏幕上显示不出来字符串"hello world!"。

 

首先介绍一下UNIX里面关于标准IO的几种缓冲机制:

1、全缓冲 。全缓冲指的是系统在填满标准IO缓冲区之后才进行实际的IO操作;注意,对于驻留在磁盘上的文件来说通常是由标准IO库实施全缓冲。

2、行缓冲 。在这种情况下,标准IO在输入和输出中遇到换行符时执行IO操作;注意,当流涉及终端的时候,通常使用的是行缓冲。

3、无缓冲 。无缓冲指的是标准IO库不对字符进行缓冲存储;注意,标准出错流stderr通常是无缓冲的。 

 

其次介绍一下几个退出函数:

1、exit ()。调用exit函数之后,它首先会执行一系列的清理处理,隐含会对存储在缓冲区内的数据进行冲洗,包括调用执行各终止处理程序,关闭所有标准IO流,然后进入内核。

2、_exit ()。与exit不同的是,它不进行清理工作而直接进入内核。此函数由POSIX.1说明,放在unistd.h里面。

3、_Exit ()。同样,它也不进行清理工作而直接进入内核。此函数跟exit一样由ISO C说明,放在stdlib.h里面。

 

现在回过头来看上面的那段代码,很容易发现,由于printf函数是行缓冲的(因为它要往终端输出数据),而且要打印的字符串不带换行符,因此在它没有遇到换行符或者没有填满缓冲区之前不会进行实际的IO操作,而紧接下来的_Exit函数又立即进入内核没有处理IO缓冲区,所以我们在终端上看不到hello world语句

 

下面介绍设置文件缓冲区函数

  void setbuf(FILE *stream,char *buf);

  void setvbuf(FILE *stream,char *buf,int type,unsigned size);

  这两个函数将使得打开文件后,用户可建立自己的文件缓冲区,而不使用fopen()函数打开文件设定的默认缓冲区。  

  对于setbuf()函数,buf指出的缓冲区长度由头文件stdio.h中定义的宏BUFSIZE的值决定,缺省值为512字节。当选定buf为空时,setbuf函数将使的文件I/O不带缓冲。而对setvbuf函数,则由malloc函数来分配缓冲区。参数size指明了缓冲区的长度(必须大于0),而参数type则表示了缓冲的类型,其值可以取如下值:

type 值 含义

  _IOFBF 文件全部缓冲,即缓冲区装满后,才能对文件读写

  _IOLBF 文件行缓冲,即缓冲区接收到一个换行符时,才能对文件读写

  _IONBF 文件不缓冲,此时忽略buf,size的值,直接读写文件,不再经过文件缓冲区缓冲

 

在《C陷阱和缺陷》一书中,讲到一个setbuf的陷阱:

程序输出有两种方式:一种是即时处理方式,另一种是先暂存起来,然后再大块写入的方式,前者往往造成较高的系统负担。因此,c语言实现通常都允许程序员进行实际的写操作之前控制产生的输出数据量。

这种控制能力一般是通过库函数setbuf实现的。如果buf是一个大小适当的字符数组,那么:

setbuf(stdout,buf);

语句将通知输入/输出库,所有写入到stdout的输出都应该使用buf作为输出缓冲区,直到buf缓冲区被填满或者程序员直接调用fflush(译注:对于由写操作打开的文件,调用fflush将导致输出缓冲区的内容被实际地写入该文件),buf缓冲区中的内容才实际写入到stdout中。缓冲区的大小由系统头文件<stdio.h>中的BUFSIZ定义。

下面的程序的作用是把标准输入的内容复制到标准输出中,演示了setbuf库函数最显而易见的用法:

#include <stdio.h>

 

main()

{

int c;

char buf[BUFSIZ];

setbuf(stdout, buf);

    while((c=getchar())!=EOF)

        putchar(c);

}

    遗憾的是,这个程序是错误的,仅仅是因为一个细微的原因。程序中对库函数setbuf的调用,通知了输入/输出库所有字符的标准输出应该首先缓存在buf中。要找到问题出自何处,我们不妨思考一下buf缓冲区最后一次被清空是在什么时候?答案是在main函数结束之后,作为程序交回控制给操作系统之前C运行时库所必须进行的清理工作的一部分。但是,在此之前buf字符数组已经被释放!

    要避免这种类型的错误有两种办法。第一种办法是让缓冲数组成为静态数组,既可以直接显式声明buf为静态:

static char buf[BUFSIZ];

也可以把buf声明完全移到main函数之外。第二种办法是动态分配缓冲区,在程序中并不主动释放分配的缓冲区(译注:山于缓冲区是动态分配的,所以main函数结束时并不会释放该缓冲区,这样C运行时库进行清理工作时就不会发生缓冲区已释放的情况):

char *malloc();

setbuf(stdout,malloc(BUFSIZ));

    如果读者关心一些编程“小技巧”,也许会注意到这里其实并不需要检查malloc函数调用是否成功。如果malloc函数调用失败,将返回一个null指针。setbuf函数的第二个参数取值可以为null,此时标准输出不需要进行缓冲。这种情况下,程序仍然能够工作,只不过速度较慢而已。

分享到:
评论

相关推荐

    Unix I/O 小结

    Unix I/O系统是操作系统的核心部分,它...总之,Unix的I/O机制涉及从底层的系统调用到高级的缓冲机制,提供了丰富的功能和优化手段,以适应不同场景的需求。理解和掌握这些知识对于进行高效和可靠的Unix编程至关重要。

    The_design_of_the_unix_operating_system.pdf(文字版)

    缓冲区缓存是Unix内核用于提高文件系统性能的一种机制。它缓存最近读写的磁盘块数据到内存中,减少对物理磁盘的访问次数,从而提升效率。 缓冲池结构(3.2缓冲池结构): 缓冲池是内核中用于管理缓存数据的内存区域...

    UNIX环境高级编程+UNIX网络编程卷1.PDF版

    书中深入讨论了文件描述符、缓冲I/O、非阻塞I/O和异步I/O,这些都是高效处理文件和设备的关键。 4. **内存管理**:在UNIX中,程序员可以直接管理内存,通过malloc和free等函数进行动态内存分配和释放。书中详细阐述...

    Unix编程艺术中文版(非加密,带目录)

    学习如何避免常见的安全漏洞(如缓冲区溢出)对于任何Unix程序员来说都是必不可少的。 综上所述,《Unix编程艺术中文版》这本书很可能是一本全面介绍Unix编程知识和技术的手册。无论是对于初学者还是有一定经验的...

    UNIX环境高级编程.pdf

    ### UNIX环境高级编程知识点概述 #### 一、UNIX基础知识 **1.1 引言** 在计算机科学领域,操作系统作为连接硬件与软件的桥梁,为...通过本书的学习,读者能够深入了解UNIX系统的工作机制,掌握高效的程序设计技巧。

    UNIX环境高级编程-pdf

    信号处理是UNIX系统中用于进程间通信和异常处理的重要机制。《UNIX环境高级编程》详细解释了信号的概念、发送、接收和处理,以及信号在进程控制中的应用,帮助读者理解如何优雅地处理程序中断和异常情况。 此外,书...

    Unix网络编程英文版PDF

    书中探讨了不同操作系统上缓冲区大小和限制,以及网络编程中常见的错误处理方法。 对于初学者来说,书中从一个简单的daytime客户端和服务器的例子出发,逐步讲解了如何使用各种套接字接口进行网络编程。通过这些...

    UNIX环境高级编程 pdf高清版

    标准输入输出的处理、缓冲机制、以及重定向技术是UNIX编程中的经典话题。书中对这些基础概念的介绍不仅全面,而且深入,使读者能够熟练掌握UNIX环境下的I/O操作。 信号处理是UNIX编程中的一个高级话题。作者在书中...

    Unix操作系统设计

    这本书深入浅出地介绍了Unix操作系统的内部工作机制,为读者提供了设计和实现一个现代操作系统所需的知识框架。以下是对书中的关键知识点进行的详细阐述: 1. **操作系统概述**:Unix操作系统是多用户、多任务的分...

    unix网络编程一二卷

    这本书主要围绕Unix系统的套接字接口进行讲解,套接字(Sockets)是Unix系统中实现进程间通信(IPC)的一种重要机制,也是网络通信的基础。书中详细阐述了以下核心知识点: 1. **网络通信基础**:介绍了网络的基本...

    Advanced Programming in the UNIX Environment 3rd Edition

    总的来说,《Advanced Programming in the UNIX Environment》第三版是一本全面且深入的Unix编程指南,适合有经验的程序员以及希望深入理解Unix/Linux系统机制的初学者。无论你是开发服务器端应用、网络服务还是进行...

    莱昂氏unix源代码分析.rar

    《莱昂氏Unix源代码分析》是一本深入探讨Unix操作系统内核的权威著作,它为读者揭示了Unix系统的核心机制和设计哲学。Unix系统自20世纪70年代诞生以来,以其简洁、高效和可移植性的特点,在科技领域中扮演着重要角色...

    Unix环境高级编程

    还涵盖了标准I/O库和缓冲机制,以及异步I/O和磁盘I/O性能优化。 4. **信号处理**:详述了Unix中的信号机制,包括信号的发送、接收、处理和屏蔽,以及它们在进程控制和异常处理中的应用。 5. **网络编程**:讨论了...

    unix system programming in ocaml

    - **`Unix.write fd buf off len`**:从缓冲区`buf`的偏移量`off`处写入最多`len`字节到文件描述符`fd`。 ##### 2.8 关闭描述符 在完成所有操作后,应该关闭文件描述符,以释放资源。 - **`Unix.close fd`**:...

    unix环境高级编程(英文)

    了解其内部机制和如何利用缓冲机制提高效率是高级编程的一部分。 5. **内存管理**:包括动态内存分配、内存映射、共享内存等,这些都是在Unix环境下高效编程的关键技能。 6. **网络编程**:Unix支持丰富的网络通信...

    unix的一些examples

    Unix采用流式I/O模型,支持缓冲区机制,可以提高文件操作效率。同时,Unix还支持文件描述符的概念,每个打开的文件或设备都有一个唯一的数字标识符。 3. **File System**: Unix的文件系统是层次结构的,所有资源...

    操作系统课程设计--有限缓冲区问题的实现

    本程序实现有限缓冲区问题,设计了两个进程,...有限缓冲区问题的实现,其目的是为了了解UNIX的命令及格式,熟悉UNIX的常用基本命令以及相关的编译器。本程序用gcc、gdb编译、调试C程序,编写程序实现有限缓冲区问题。

    UNIX环境高级编程

    《UNIX环境高级编程》是一本深入探讨UNIX操作系统核心机制与编程接口的经典著作。该书旨在为程序员提供在UNIX系统上进行高效开发所需的全面知识,涵盖了从基本概念到复杂操作的各种主题。 1. **UNIX系统概述**:...

    UNIX环境高级编程(中文第三版.zip

    9. **信号**:介绍Unix信号机制,用于进程间通信和异常处理,如`signal()`, `raise()`, 和`sigaction()`等函数。 10. **进程环境**:涉及环境变量的使用,以及如何改变和获取进程环境。 11. **编译和链接**:解释...

    Unix操作系统源码分析

    通过详细分析源代码,本书旨在揭示Unix系统的工作原理,帮助读者掌握其核心机制,从而提升在Unix环境下的编程能力。 Unix操作系统自1960年代末诞生以来,就以其简洁、高效的设计理念,成为计算机科学领域的重要里程...

Global site tag (gtag.js) - Google Analytics