《APUE》第三章笔记(3)
文件共享
UNIX系统支持在不同进程中共享打开的文件,首先先用一幅apue的图来介绍一下内核用于I/O文件的数据结构:
如图所见,一个进程都会有一个记录项,记录项中包含有一张打开文件描述符表,每个描述符占用一项。
描述符包括:(a)文件描述符标志(fd标志),(b)指向一个文件表项的指针(文件指针)。
而文件表包括:(a)文件状态标志,(b)当前文件偏移量,(c)v节点指针
v节点包括:文件类型和对此文件进行各种操作的函数的指针,大部分v节点还包括年i节点(索引节点,第四章详细介绍)
如果两个进程各自打开同一个文件的话,文件表是的分开的,但v节点是共享的:
文件表分开是因为:使每个进程都有它自己的对该文件的当前文件偏移量。
这样,当多个进程写同一个文件时,就有可能出问题。Let me tell you why.
早期的UNIX没有O_APPEND追尾选项,所以写到文件的结尾是这样做的:
if (lseek(fd, 0L, 2) < 0) /* 定位到文件的末端 */
err_sys("lseek error");
if (write(fd, buf, 100) != 100) /* 追尾写100字节 */
err_sys("write error");
这样对单个进程来说是没有问题的。但是对于多个进程对同一个文件同时使用这种方法就会出错了。
比如A和B进程同时打开一个文件,假定A调用了lseek,它将进程A的该文件当前偏移量设置为1500字节(文件末尾处),然后内核切换B进程运行,B也是调用lseek也将该文件的当前偏移量设置为1500字节(文件末尾处,记住,每个进程并不是共享同一个当前文件偏移量的),然后B调用了write函数,将当前偏移量曾至1600字节。因为该文件的长度已经增加了,所以内核对v节点中的当前文件长度更新为1600。然后内核切回A进程,当A调用write时,就从当前文件偏移量(1500字节)处将数据写到文件中去,这样也就代换了进程B
刚写到该文件中的数据。
问题出在逻辑操作“先定位到文件尾端处,然后写“上,它使用了两个分开的函数调用。解决的方法就是使这两个操作变成一个操作(这也就叫做原子操作)。任何一个需要多个函数的操作都不可能是原子操作,因为在两个函数调用之间,内核都有可能临时挂起该进程(如上面所加假定的)。
UNIX提供了一种方法使这种操作成为原子操作,该方法就是在打开文件时设置O_APPEND标志。这就使内核每次对这种文件进行写之前,都将进程的当前文件偏移量设置到该文件的尾端处,于是每次写之前就不用再调用lseek。
一般而言,原子操作(atomic operation)指的时由多步组成的操作。如果该原子操作执行,则要么时执行完所有步骤,要么一步也不执行,不可能只执行所有步骤的一个子集。(只要理解原子是不可分的就行了)
第三章笔记待续。
《APUE》第三章笔记(3)的更多相关文章
- 《APUE》第三章笔记(2)
read函数 调用read函数从打开的文件中读数据. #include <unistd.h> ssize_t read(int filedes, void *buf, size_t nby ...
- 《APUE》第三章笔记(1)
以下内容是我看<APUE>第二版第三章的笔记,有错还希望指出来,谢谢. unbuffered I/O,跟buffered I/O相对,buffered I/O就是 ISO C标准下的标准输 ...
- 【转】《APUE》第三章笔记(4)及习题3-2
原文网址:http://www.cnblogs.com/fusae-blog/p/4256794.html APUE第三章的最后面给出的函数,现在还用不着,所以,先留个名字,待到时候用着了再补上好了. ...
- 《APUE》第三章笔记(4)及习题3-2
APUE第三章的最后面给出的函数,现在还用不着,所以,先留个名字,待到时候用着了再补上好了. dup和dup2函数:用来复制文件描述符的 sync函数,fsync函数和fdatasync函数:大致的功 ...
- HBase in Action前三章笔记
近期接触HBase,看了HBase In Action的英文版.開始认为还行,做了些笔记.可是兴许看下去,越来越感觉到实战这本书比較偏使用上的细节,对于HBase的具体设计涉及得很少.把前三章的一些笔 ...
- 《HALCON数字图像处理》第三章笔记
目录 第三章 HALCON图像处理基础 HALCON控制语句 HALCON算子 HALCON图像处理入门 HALCON图像读取 HALCON图像显示 图形窗口 图像显示 显示文字 HALCON图像转换 ...
- [ APUE ] 第三章 文件系统
1. 文件描述符 打开或创建一个文件时,内核向进程返回一个文件描述符,当读.写一个文件时,用open()或creat()返回的文件描述符标识该文件,将其作为参数传递给write.read. stdin ...
- unix环境高级编程第三章笔记
文件描述符 1.文件描述符的概念 对于内核而言,所有打开的文件都会用一个文件描述符来引用,打开或和创建一个新文件的时候,内核会给进程返回一个文件描述符,而当使用read write时,可以使用这个文件 ...
- Vue2.5开发去哪儿网App 第三章笔记 上
1. vue 生命周期函数 每个 Vue 实例在被创建之前都要经过一系列的初始化过程.例如,实例需要配置数据观测(data observer).编译模版.挂载实例到 DOM ,然后在数据变化时更新 ...
随机推荐
- hdoj 2955 Robberies
Robberies Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total S ...
- oc学习之路----代理模式2-使用步骤
之前已经写过一个个人关于代理模式的一些看法,现在就来总结一下使用代理模式的步骤吧. 1.先搞清楚谁是谁的代理(delegate) ● 2.定义代理协议,协议名称的命名规范:控件类名 + Delegat ...
- php的fread函数的一个巨大的坑
先看看fread的manual,如下: http://php.net/manual/en/function.fread.php fread() reads up to length bytes fro ...
- java统计程序运行的时间
耗时统计 第一种是以毫秒为单位计算的.long startTime = System.currentTimeMillis(); //获取开始时间 //程序做一些功能性的操作doSomething ...
- textLayout_1.0.0.595.swz
使用ai制作的矢量素材,导出到flash里面.生成swf时.有的时候会多一个textLayout_1.0.0.595.swz的文件. 这会导致导出的swf无法加载使用.会显示不出来. 解决办法是: 检 ...
- careercup-树与图 4.9
4.9 给定一颗二叉树,其中每个结点都含有一个数值.设计一个算法,打印结点数值总和等于某个给定值的所有路径.注意,路径不一定非得从二叉树的根节点或叶子节点开始或结束. 类似于leetcode:Path ...
- Qt之QtScript(一)
C++和JavaScript相互通信.今天就学习QtScript模块吧. Qt 包含完全集成的 ECMA 标准脚本引擎.Qt Script 集成了 QObject,为脚本提供了 Qt 的信号与槽 (S ...
- 这种写法用过没:string.Format("{0,-10}", 8)
1 2 3 4 var s1 = string.Format("{0,-10}", 8); var s2 = string.Format("{0,10}", 8 ...
- 【转】Android 应用测试总结
前提所有的功能分支已完成 启动:1. 启动入口:桌面正常启动,最近运行启动,所有程序列表中启动,锁屏快捷启动2. 其他入口:从其他程序开启应用,从外部以文件形式打开应用(如果有)3. 退回:从其他程序 ...
- Windows 7 SP1 x64 旗舰版 微软官方安装U盘的制作
[ 本主题由 中山艹泥喵 于 2013-08-20 23:14:33 设为精华1,原因:不错~ ] 最后由 风中枯萎 于 2015-12-15 17:44:15 修改 安装Windows 7操作系统主 ...