linux系统编程 第三章

        作为文件系统的抽象,它是IO中最基本的概念,所有的磁盘操作都是基于块进行的。
        操作系统效率随着系统调用次数的增多而急剧下降。每次读写操作字节数太少,会导致读写次数增多而降低效率;每次读写不是块大小的整数倍,也会因为对齐数据而降低效率。
        系统调用stat可以轻松指定设备的块大小。
        现实中程序很少以块为单位进行操作,程序往往是以区域、行和单个字符为单位进行操作。为了改善这种情况,程序使用用户缓冲IO。当数据写入时,它会被存储在程序地址空间的缓冲区中。当缓冲区达到一个给定的值,整个缓冲区会在一次操作中被写出。同理,读操作一次读入缓冲区大小且块对齐的数据。当应用程序执行不对齐的读请求时,缓冲区一块一块的给出数据。最后,当缓冲区为空时,另一个大的块对齐的区域又被读入。
        一个程序究竟应该使用标准IO或是自创的用户缓冲,还是直接使用系统调用,这些都需要设计者仔细权衡程序的需求和行为后决定。
        在标准IO中,一个打开的文件叫做“流”(其实流就是一个指向FILE的指针??)。
        文件通过fopen打开以供读写操作。参数mode描述以怎样的方式打开指定文件。它可以是以下的字符串之一:r、r+、w、w+、a、a+。
        函数fdopen将一个已经打开的文件描述符转成一个流。
        fclose函数关闭一个给定的流。fcloseall函数关闭所有的和当前进程相关联的流,包括标准输入、标准输出、标准错误。
        C标准库实现了多种从流中读取数据的方法。其中最常用的是三种:单字节的读取、单行的读取、和二进制数据的读取。
        fgetc可以用来从流中读取单个字符。这个函数从流中读取下一个字符并把该无符号字符强制转换为int型返回。ungetc允许程序员偷窥流,如果你不需要该字符时,可以把它放回。如果多个字符被放入流中,它们会以倒序的方式返回。
        函数fgets从一个给定的流中读取一个字符串。这个函数从流中读取size-1个字符到str中,当所有字符读入时,空字符被存入字符串末尾。当读到EOF或者换行符时读入结束。如果读到一个换行符,“\n”被存入str。
        调用fread用来读二进制数据。
        所有的机器设计都有数据对弃的要求。C变量的存储和访问都要是地址对齐的。在处理结构体,手动执行内存管理,向磁盘存储二进制数据,进行网络通信时,对齐都非常重要。
        函数fputc用来写入单个字符。函数fputs用来往给定的流中写入一个完整的字符串。fwrite函数用来写入二进制数据。
        函数fseek是标准IO最常用的定位函数,操纵流指向文件中由offset和whence指定的位置。函数fsetpos将流的位置设置到pos处。函数rewind将位置重置到流的初始位置,并且清空错误标记。ftell函数返回当前流的位置。标准输入输出还提供了fgetpos函数,成功时,fgetpos返回0,并且将当前流的位置设置为pos。
        标准IO库提供了fflush函数,将用户缓冲区写入内核,并且保证所有的数据都通过write写出。如果stream是空的,所有进程打开的流会被清洗掉。
        本章所提到的所有调用的缓冲区都是通过C函数库来维护的,他们保留在用户空间中,而不是内核空间。这样可以提高效率,程序保留在用户空间中,并且运行用户的代码,不执行系统调用。只有当磁盘或者其他介质必须被访问时系统调用才会被执行。fflush只是把用户缓冲的数据写入到内核缓冲区。这并不保证数据能够写入物理介质。
        函数ferror测试是否在流上设置了错误标志,错误标志由其它响应错误的标准IO函数设置。函数feof测试文件结尾标志是否被设置。函数clearerr为流清空错误和文件结尾标志。
        函数fileno用来获得流的文件描述符。
        标准IO实现了三种用户缓冲,而且为开发者提供了一个用来控制缓冲区大小和类型的接口:
        不缓冲:没有执行用户缓冲,数据直接提交到内核。标准错误默认是不缓冲的。
        行缓冲:缓冲以行为单位执行。
        块缓冲:缓冲以块为单位执行。默认的所有和文件相关的流都是块缓冲的。标准IO称块缓冲为全缓冲。
        函数setvbuf设置流的缓冲类型模式。
        
        线程的定义是共享同一地址空间的多个进程。如果不采取数据同步措施或将数据线程私有化,线程可以任何时间修改共享数据。支持线程的操作系统提供加锁机制(保证相互排斥的程序结构)来保证线程不会互相干扰。
        标准IO的函数本质上是线程安全的。在内部实现中,设置了一把锁,一个锁计数器,和为每个打开的流创建的所有者线程。一个线程要想执行任何IO请求,必须首先获得锁而且成为所有者线程。
        当然在实际应用中,许多应用程序需要比单独的函数调用更强的原子性。
        
        函数flockfile会等待流被解锁,然后获得锁,增加锁计数,成为流的所有者线程,然后返回。
        函数funlockfile减少与流相关的锁计数。
        如果锁计数器达到了0,当前的线程放弃流的所有权,另一个线程现在能获得锁。
        函数ftrylockfile是flockfile的非堵塞版本。如果流当前加了锁,ftrylockfile不做任何处理,并立即返回一个非零值。如果流当前没有加锁,它获得锁,增加锁计数,成为流的所有者线程,并且返回0。
        linux提供了一些不加锁的标准IO函数,这些函数类似通常的标准IO函数,但是不执行任何锁操作。这样可以通过程序员的手动加锁,来提高运行的效率。
























        

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值