基本概念

内核使用3个数据结构描述一个打开的文件:进程表、文件表、V节点表
首先了解3种数据结构的概念
    1 进程表
        每一个进程有一个进程表。进程表里是一组打开的文件描述符,如标准输入0,标准输出1,标准错误2...
    2 文件表
        进程打开一个文件时,内核就为该文件创建一个文件表。
        进程表对文件表一般是 一对多的关系    文件表对文件描述符也是一对多的关系(可能多个文件描述符指向同一文件表)
(这里解释下为什么进程表和文件表一对多的关系只是一般情况下,有什么特殊情况呢?  当父进程fork一个子进程时,复制了它的进程表,导致多个进程表对一个文件表)
         文件表中包含了文件状态标志、当前偏移量、和V-node
pointer表项
        
   文件状态标志如:read,  write,  append,  sync, nonblocking等等
            偏移量好理解,就不多解释了(它在write时会变化)
            V-node
pointer就是指向V-node表的指针
        
    3 V节点表(Linux只有i节点表)
        每一个没打开的文件有一个V节点表。V-node table实际上跟进程关系不大,主要跟被打开的文件相关。一个打开的文件只有一个v-node表,所有打开它的进程共用此表
        文件表对V节点表示多对一的关系。
        V-node表主要是描述了文件信息、数据的访问入口

一个进程打开多个文件


    如《APUE E3rd》的Figure3.7所示,一个进程打开多个文件。
    文件描述符0和1各通过一个文件表打开一个文件
    注:可能文件描述符0和3指向同一个文件表

多个进程打开一个文件

    
    如《APUE E3rd》中figure 3.8所示,两个进程打开同一个文件。
    两个进程使用的文件表都是进程独有的。也就是说一个文件表虽然是内核维护的,但它至属于某一个特定进程。

fcntl

    功能描述:通过文件描述符来操作文件的属性。
    形式:
#include <fcntl.h>
int fcntl(int fd,int cmd,... /* intarg */ );
Returns: depends on cmd if OK (see following),−1 on error

    描述:fcntl()可以改变已打开文件的性质。参数fd是一打开的文件描述符,cmd是特定的命令,第三个参数是否存在取决于cmd的值。第三个参数如果存在一般为整形,也可能是struct flock *类型的结构体指针。
    返回值:返回值是否存在也取决于cmd,一般错误返回-1,F_DUPFD , F_GETFD , F_GETFL以及F_GETOWN会返回文件描述符或者文件的一些属性。
    一般在下面五种情况下使用fcntl()函数
    1. 复制一个已存在的文件描述符(cmd=F_DUPFD、F_DUP、FD_CLOEXEC)
    2. 取得/设置已存在文件描述符的标志(cmd=F_GETFD、F_SETFD)
    3. 取得/设置已存在文件描述符的状态标志(cmd=GETFL、SETFL)
    4. 取得/设置异步I/O时文件的所有权(cmd=GETOWN、SETOWN+)
    5. 取得/设置异步锁(cmd=GETLK、SETLK、SETLKW)
    文件标志位:进程表中每一条记录都对应了一个文件描述符的fd标志位和指向文件表的指针,fd标志位目前只定义了FD_CLOEXEC一项。因此,fd标志位就是FD_CLOEXEC

cmd参数

F_DUPFD:
    复制一个已存在的文件描述符,新文件描述符作为函数的返回值,其取值一般是不小于3且还没被打开的文件描述符。新旧两个文件描述符共享文件表,但是两个描述符有不同的fd标志位(进程表中每一个表项记录了一个文件描述符的fd标志位和指向文件表的指针)。使用F_DUPFD时,fd标志位的FD_CLOEXEC将被清零①  
F_DUPFD_CLOEXEC
    复制一个已存在的文件描述符,与F_DUPFD不同之处在于其设置了FD_CLOEXEC。也就是在使用exec是文件被关闭。
F_GETFD
    返回文件标志位,目前文件标志位只定义了FD_CLOEXEC,因此返回值就是FD_CLOEXEC的值。
F_SETFD
    设置文件标志位(即设置FD_CLOEXEC),设置的值在第三个参数。
F_GETFL
    返回该文件描述符对应的文件状态标志位file status flag。文件状态标志位主要有O_RDONLY、O_WRONLY,本文后面进一步讨论。
F_SETFL
    设置文件状态标志。只有O_APPEND、O_NONBLOCK、O_SYNC、O_DSYNC、O_RSYNC、O_FSYNC、O_ASYNC其中状态标志可以被更改(设置)。
F_GETOWN
    取得当前正在接收SIGIO或者SIGURG信号的进程id或进程组id,进程组id返回的是负值(arg被忽略)
F_SETOWN
    设置将接收SIGIO和SIGURG信号的进程id或进程组id,进程id和进程组id通过第三个参数arg传入(只能传一个,要么进程id,要么进程组id),arg为正值表示传入的是进程id,arg为负值则传入的是进程组id。
F_GETLK    
    取得文件的锁定状态,如果被锁定了,则将锁定信息重写到第三个参数arg(一个指向flock的结构体的指针)。如果未被锁定状态,则除了struct flock的l_type被设置为F_UNLCK外,其他成员不变。 
F_SETLK    
    通过第三个参数arg(struct flock*)锁定文件。如果read lock和write lock设置失败,则返回EACCES  or  EAGAIN
F_SETLKW   
   类似F_SETLK,不同的是当设置锁发生阻塞时,它会等待(W是wait的意思),直至设置锁完成




文件状态标志



    O_RDONLY , O_WRONLY与O_RDWR 还有后面的O_EXEC、O_SEARCH并不是每一项占一位的,因此,在获取文件状态时,为取得文件当前的存取模式,需要用O_ACCMODE与F_GETFL操作返回的值进行与运算
    关于文件标志位的值,如下在系统头文件fcntl.h(我的熊中是/usr/include/i386-linux-gnu/bits/fcntl)
/* open/fcntl - O_SYNC is only implemented on blocks devices and on files
located on a few file systems. */
#define O_ACCMODE 0003
#define O_RDONLY 00
#define O_WRONLY 01
#define O_RDWR 02
#define O_APPEND 02000
#define O_NONBLOCK 04000
#define O_NDELAY O_NONBLOCK
#define O_SYNC 04010000
#define O_FSYNC O_SYNC
#define O_ASYNC 020000

可以看到《APUE》中关于O_SYNC的讨论实际上代码中已经有给出注释。

结构体指针 struct flock*

struct flock {
short l_type; /* F_RDLCK, F_WRLCK, or F_UNLCK */
short l_whence; /* SEEK_SET, SEEK_CUR, or SEEK_END */
off_t l_start; /* offset in bytes, relative to l_whence */
off_t l_len; /* length, in bytes; 0 means lock to EOF */
pid_t l_pid; /* returned with F_GETLK */
};


注解:
①    FD_CLOEXEC为0时,表示使用exec函数族时文件描述符fd会被传入exec()创建的新进程,如果FD_CLOEXEC为1,则文件被关闭




APUE学习笔记——3.文件共享与fcntl介绍的更多相关文章

  1. APUE学习笔记3_文件IO

    APUE学习笔记3_文件IO Unix中的文件IO函数主要包括以下几个:open().read().write().lseek().close()等.这类I/O函数也被称为不带缓冲的I/O,标准I/O ...

  2. APUE学习笔记——10.9 信号发送函数kill、 raise、alarm、pause

    转载注明出处:Windeal学习笔记 kil和raise kill()用来向进程或进程组发送信号 raise()用来向自身进程发送信号. #include <signal.h> int k ...

  3. 【转】Pandas学习笔记(一)基本介绍

    Pandas学习笔记系列: Pandas学习笔记(一)基本介绍 Pandas学习笔记(二)选择数据 Pandas学习笔记(三)修改&添加值 Pandas学习笔记(四)处理丢失值 Pandas学 ...

  4. NGUI学习笔记(一)UILabel介绍

    来个前言: 作为一个U3D程序员,自然要写一写U3D相关的内容了.想来想去还是从UI开始搞起,可能这也是最直观同时也最重要的部分之一了.U3D自带的UI系统,也许略坑,也没有太多介绍的价值,那么从今天 ...

  5. apue学习笔记(第十三章 守护进程)

    本章将说明守护进程结构,以及如何编写守护进程程序. 守护进程,也就是通常说的Daemon进程,是Unix中的后台服务进程.它是一个生存期较长的进程,通常独立于控制终端并且周期性地执行某种任务或等待处理 ...

  6. Android自动化学习笔记之MonkeyRunner:官方介绍和简单实例

    ---------------------------------------------------------------------------------------------------- ...

  7. 【JAVAWEB学习笔记】07_BootStrap、Viewport介绍

    今天主要学习了BootStrap,viewport的介绍和最后对网站进行了重构 今天晨读单词: Compatible:兼容性 viewport:视口 device:设备 initial:初始化(缩写i ...

  8. apue学习笔记(第十四章 高级I/O)

    本章涵盖了从多概念和函数:非阻塞I/O.记录锁.I/O多路转换.异步I/O.readv和writev函数以及存储映射I/O 非阻塞I/O 非阻塞I/O使我们可以发出open.read和write这样的 ...

  9. APUE学习笔记——3.10文件共享

    基本概念 内核使用3个数据结构描述一个打开的文件:进程表.文件表.V节点表 首先了解3种数据结构的概念     1 进程表         每一个进程有一个进程表.进程表里是一组打开的文件描述符,如标 ...

随机推荐

  1. ajax的认识

    1. ajax是一种技术,无需刷新页面即可向服务器传输.读写数据. 2. ajax的参数说明: 1.url: 要求为String类型的参数,(默认为当前页地址)发送请求的地址. 2.type: 要求为 ...

  2. 让boost.variant支持lambda表达式访问

    前言 之前写个过一篇博客叫<浅谈boost.variant的几种访问方式>,里面讲到了可以通过访问者方式来获取variant的值,但是在重载函数operator()里面只能够获取varia ...

  3. 算法+OpenCV】基于opencv的直线和曲线拟合与绘制(最小二乘法)

    http://blog.csdn.net/guduruyu/article/details/72866144 最小二乘法多项式曲线拟合,是常见的曲线拟合方法,有着广泛的应用,这里在借鉴最小二乘多项式曲 ...

  4. Java对map进行排序并生成序号

    最近做的项目有这样一个需求:要求对map中的值进行排序并生成序号.如果值相等则序号不变:如果不相等序号为该数数值在所有元素中的索引.如下表所示: Key(String) Value(Float) Id ...

  5. 如何为openwrt中的某个模块生成PKG_MIRROR_HASH

    答:介绍两种方法,第一种自动生成(当然使用自动的啦),第二种手动生成 第一种方法: 1.在软件包的Makefile中让此项写成这样PKG_MIRROR_HASH:=skip  (如果不加上skip,那 ...

  6. Spring Boot 中yml配置文件

    步骤一:yml格式 现在大家发现,在springboot里还是要用到配置文件的. 除了使用.properties外,springboot还支持 yml格式. 个人觉得yml格式的可读性和..prope ...

  7. LeetCode——Increasing Triplet Subsequence

    Question Given an unsorted array return whether an increasing subsequence of length 3 exists or not ...

  8. 一次http请求,谁会先断开TCP连接?什么情况下客户端先断,什么情况下服务端先断?

    我们有2台内部http服务(nginx): 201:这台服务器部署的服务是account.api.91160.com,这个服务是供前端页面调用: 202:这台服务器部署的服务是hdbs.api.911 ...

  9. 字符串与byte[]之间的转换

    一.  编码 同一个字符在不同的编码下会被编成不同长度的编码,比如: ACSII,每个字符对应一个字节,实际上只使用了7位,从00h-7Fh.只能表达128个字符. GB2312,中文的一种编码,每个 ...

  10. [转]检测SQLSERVER数据库CPU瓶颈及内存瓶颈

    在任务管理器中看到sql server 2000进程的内存占用,而在sql server 2005中,不能在任务管理器中查看sql server 2005进程的内存占用,要用 以下语句查看sql se ...