文件共享

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)的更多相关文章

  1. 《APUE》第三章笔记(2)

    read函数 调用read函数从打开的文件中读数据. #include <unistd.h> ssize_t read(int filedes, void *buf, size_t nby ...

  2. 《APUE》第三章笔记(1)

    以下内容是我看<APUE>第二版第三章的笔记,有错还希望指出来,谢谢. unbuffered I/O,跟buffered I/O相对,buffered I/O就是 ISO C标准下的标准输 ...

  3. 【转】《APUE》第三章笔记(4)及习题3-2

    原文网址:http://www.cnblogs.com/fusae-blog/p/4256794.html APUE第三章的最后面给出的函数,现在还用不着,所以,先留个名字,待到时候用着了再补上好了. ...

  4. 《APUE》第三章笔记(4)及习题3-2

    APUE第三章的最后面给出的函数,现在还用不着,所以,先留个名字,待到时候用着了再补上好了. dup和dup2函数:用来复制文件描述符的 sync函数,fsync函数和fdatasync函数:大致的功 ...

  5. HBase in Action前三章笔记

    近期接触HBase,看了HBase In Action的英文版.開始认为还行,做了些笔记.可是兴许看下去,越来越感觉到实战这本书比較偏使用上的细节,对于HBase的具体设计涉及得很少.把前三章的一些笔 ...

  6. 《HALCON数字图像处理》第三章笔记

    目录 第三章 HALCON图像处理基础 HALCON控制语句 HALCON算子 HALCON图像处理入门 HALCON图像读取 HALCON图像显示 图形窗口 图像显示 显示文字 HALCON图像转换 ...

  7. [ APUE ] 第三章 文件系统

    1. 文件描述符 打开或创建一个文件时,内核向进程返回一个文件描述符,当读.写一个文件时,用open()或creat()返回的文件描述符标识该文件,将其作为参数传递给write.read. stdin ...

  8. unix环境高级编程第三章笔记

    文件描述符 1.文件描述符的概念 对于内核而言,所有打开的文件都会用一个文件描述符来引用,打开或和创建一个新文件的时候,内核会给进程返回一个文件描述符,而当使用read write时,可以使用这个文件 ...

  9. Vue2.5开发去哪儿网App 第三章笔记 上

    1.  vue 生命周期函数 每个 Vue 实例在被创建之前都要经过一系列的初始化过程.例如,实例需要配置数据观测(data observer).编译模版.挂载实例到 DOM ,然后在数据变化时更新 ...

随机推荐

  1. 扯谈网络编程之Tcp SYN flood洪水攻击

    简单介绍 TCP协议要经过三次握手才干建立连接: (from wiki) 于是出现了对于握手过程进行的攻击.攻击者发送大量的SYN包,server回应(SYN+ACK)包,可是攻击者不回应ACK包,这 ...

  2. nginx 安装手记 分类: Nginx 服务器搭建 2015-07-14 14:28 15人阅读 评论(0) 收藏

    Nginx需要依赖下面3个包 gzip 模块需要 zlib 库 ( 下载: http://www.zlib.net/ ) zlib-1.2.8.tar.gz rewrite 模块需要 pcre 库 ( ...

  3. (BUG已修改,最优化)安卓ListView异步加载网络图片与缓存软引用图片,线程池,只加载当前屏之说明

    原文:http://blog.csdn.net/java_jh/article/details/20068915 迟点出更新的.这个还有BUG.因为软引应不给力了.2.3之后 前几天的原文有一个线程管 ...

  4. SQL Server数据库同步SQL

    select table_name,COLUMN_NAME,data_TYPE,CHARACTER_OCTET_LENGTH,CHARACTER_MAXIMUM_LENGTH from informa ...

  5. [ES6] 23. Rest Parameters & Spread Parameters

    Rest Parameters: In ES5, when you don't know how many paramters will be passed in, you can use argum ...

  6. PreferenceActivity 自动保存属性

    package com.example.preference; import android.content.Context; import android.os.Bundle; import and ...

  7. PHP正值表达式

    一个正值表达式是有四部分组成分别是 1.定界符 //是最常用的定界符 其实除了数组字母下划线以外其他的什么都可以作为定界符 2.原子:最小的一个匹配单位 放在定界符中  在一个正值表达式中至少要有一个 ...

  8. JS 时间与时间戳的相互转换

    <script type="text/javascript"> var time = "2015-04-22 21:41:43";//2015-4- ...

  9. 加快modelsim仿真速度的方法(原创)

    ①仿真精度越高,仿真效率月底. 仿真时采用`timescale 1ns/1ns比采用1ns/100ps的仿真效率高 simulation was two billion ns. ②clock gene ...

  10. SMTP ERROR: Password command failed: 535 Incorrect authentication data

    在处理一个使用PHPMailer来发送电邮,我在本地使用我的163邮箱来做测试发送电邮,能够成功的发送电邮:当上传到正式平台时,出现了,类似这样的错误信息 SMTP ERROR: Password c ...