开发日记-20190827 关键词 读书笔记《Unix环境高级编程(第二版)》DAY 3

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/qq_31433709/article/details/100086439

Referred Blogs

文件描述符标志,文件状态标志
Linux中文件描述符fd和文件指针flip的理解
Linux编程–文件描述符fd


文件共享

Unix支持在不同进程间共享文件。
内核使用了三种数据结构,他们之间的关系决定了在文件共享方面一个进程对另一个进程可能产生的影响。
(1)每个进程在进程表中都有一个记录项,每个记录项中有一张打卡的文件描述符表,可将其视为一个矢量,每个每个描述符占用一项。与每个文件描述符相关联的是:
(a)文件描述符标志。
(b)指向一个文件表项的指针。

(2)内核为所有打开文件维持同一张文件表。每个文件表项包含:
(a)文件状态标志(读,写,增写,同步,非阻塞等)。
(b)当前文件位移量。
(c)指向该文件v节点表项的指针。

(3)每个打开文件(或设备)都有一个v节点结构。v节点包含了该文件类型和对此文件进行各种操作的函数的指针信息。对于大多属于文件,v节点还包含了该文件的i节点(索引节点)。这些信息是打开文件时从盘上读入内存的,所以所有关于文件的信息都是快速可供使用的。例如,i节点包含了文件的所有者,文件长度,文件所在的设备,指向文件在盘上所使用的实际数据块的指针等等。

  • 在完成每个write后,在文件表项中的当前文件位移量即增加所写的字节数.如果这使当前文件位移量超过了当前文件长度,则在i节点表项中的当前文件长度被设置为当前文件位移量(也就是该文件加长了)

  • 如果用O_APPEND标志打开了一个文件,则相应标志也被设置到文件表项的文件状态标志中.每次对这种据具有添写标志的文件执行写操作时,在文件表项中的当前文件位移量首先被设置为i节点表项中的文件长度.这就使得每次写的数据都添加到文件的当前尾端处.

  • lseek函数只修改文件表项中的当前文件位移量,没有进行任何IO操作

  • 若一个文件用lseek被定位到文件当前的尾端,则文件表项中的当前位移量被设置为i节点表项中的当前文件长度

可能有多个文件描述符项指向用一个文件表项.在fork后也发生同样的情况,此时父,子进程对于每一个打开的文件描述符共享同一个文件表项.

注意,文件描述符标志和文件状态标志在作用范围方面的区别,前者只用于一个进程的一个描述符,而后者则适用于指向该给定文件表项的任何进程中的所有描述符.

上述的一切对于多个进程读同意文件都能正确工作.每个进程都有它自己的文件表项,其中也有它自己的当前文件位移量.但是,当多个进程写同一文件时,则可能产生预期不到的结果.为了说明如何避免这种情况,需要理解原子操作的概念.

考虑一个进程,它要将数据添加到一个文件尾端.早期的UNIX版本并不支持open的O_APPEND选择项,所以程序被编写成下列形式:

if(lseek(fd,0L,2)<0)err_sys("lseek error");
if(write(fd,buff,100)!=100)err_sys("write error");

对单个进程而言,这段程序能正常工作,但若有多个进程时,则会产生问题.

假定有两个独立的进程A和B,都对同一个文件进行添加操作.每个进程都以打开了该文件,但未使用O_APPEND标志.此时各数据结构之间的关系如图3-2所示一样.每个进程都有它自己的文件表项,但是共享一个v节点表项.假定进程A调用了lseek,它将对于进程A的该文件的当前位移量设置1500字节(当前文件尾端处).然后内核切换进程使进程B运行.进程B执行lseek,也将其对该文件的当前位移量设置为1500字节(当前文件尾端处).然后B调用Write,它将B的该文件的当前文件位移量增至1600.因为该文件的长度已经增加了,所以内核对v节点中的当前文件长度更新为1600,.然后内核又进行进程切换使进程A回复运行.当A调用write时,就从其当前位移量(1500)处将数据写到文件中去.这样也就代换了进程B刚写到该文件中的数据.

这里的问题出在逻辑操作"定位到文件尾端处,然后写"使用了两个分开的函数调用.解决问题的方法是使这两个操作对于其他进行而言成为一个原子操作.任何一个要求多于一个的函数调用的操作都不能成为原子操作,因为在两个函数调用之间,内核有可能会临时挂起该进程.

UNIX提供了一种方法使这种操作成为原子操作,其方法就是在打开文件是设置O_APPEND标志.正如前一节所说,这就是内核每次对这种文件进行写之前,都将进程的当前位移量设置到该文件的尾端处,于是每次写之前就不再需要调用lseek.


fcntl函数

fcntl函数可以改变已经打开文件的性质

 int fcntl(int filedes, int cmd, ...);

在本节的各实例中,第三个参数总是一个整数,与上面的所示函数原型中的注释部分相对应.但是12.3节说明记录锁时,第三个参数则是指向同一个结构的指针.


以上是《Unix环境高级编程》关于文件访问和控制的相关记录和具体内容,实际上看的时候总感觉缺了一点什么,所以还是倾向于在网上搜索一些博客内容中搜点补充内容,稍微给这些干瘪的内容充充气,让其变得丰满一些。
好了,让游戏的第二幕上映吧.


我感觉还是以问题的形式来理清思路会比较好:
Q1:什么是文件描述符,文件描述符标志,文件状态标志?
书上所写的内容仅仅给出了这些的名称,甚至都没有给出这些名称的概念本身,我感觉这些是远远不够的,还是应该更加清晰的了解这些概念会更好一些.
专门贴一篇内容吧,不然太乱了.
什么是文件描述符,文件描述符标志,文件状态标志

猜你喜欢

转载自blog.csdn.net/qq_31433709/article/details/100086439