Linux文件系统(二)

文件描述符与文件的关系

在虚拟地址空间中,进程将打开的文件描述符放在task_struct的文件描述符表中,文件描述符指向一个文件表项,文件表项则指向文件的i-node节点。
在这里插入图片描述i-node节点的具体结构可以参考Linux文件系统(一)中的描述,文件表项虽然是系统层面管理的,但对于相同的i-node,不同进程对应的文件表项是不同的,文件表项实际上是struct file结构体,文件描述符表就是元素为struct file的数组,同一进程中多次打开同一文件,对应的文件表项和i-node都相同,而不同进程打开同一文件,文件表项不同,i-node相同。特殊的是,父子进程共享fork前创建的文件表项。
从上图可以发现,文件表项中记录了文件偏移量,不同文件表项记录不同的文件偏移量,这就是不同进程间不会共享文件偏移量的原因。

close_on_exec

子进程fork时,会复制父进程的文件描述符和文件表项,这有可能带来意想不到的错误。比如父进程中打开了一个文件描述符,父进程fork出子进程后,子进程通过exec装载新的程序,父进程退出,此时子进程还拥有这个文件描述符,这是进程不希望看到的。
我们在创建守护进程时,通过关闭编号为0、1、2的文件描述符来避免上面的情况,但有时我们在fork之前已经打开了很多文件,需要一一关闭难免会出错,可以通过设置close_on_exec标志来避免文件描述符没有被关闭。
close_on_exec标志的语义是在fork的子进程中执行exec的时候,会自动清理掉带有close_on_exec标志的文件描述符,具体使用代码如下:

#include <unistd.h>
#include <fcntl.h>

int main(){
    int fd = open("fd", O_RDONLY|O_CLOEXEC);
    return 0;
}

或者:

#include <unistd.h>
#include <fcntl.h>

int main(){
    int fd = open("fd", O_RDONLY);
    int flags = fcntl(fd, F_GETFD);
    flags |= FD_CLOEXEC;
    fcntl(fd, F_SETFD, flags);
    return 0;
}

文件锁

在线程同步中我们介绍过互斥锁、读写锁和自旋锁,在文件操作中也有用于同步的文件锁。
如果没有文件锁,在多个进程或线程读写文件时,变化记录在内存中,磁盘上文件的最后状态只取决于最后一个写进程/线程。为了解决这种问题,Linux引入了文件锁,文件锁分为读取锁和写入锁,加锁的规则类似于读写锁,读取锁可以共享,写入锁只能独占。
文件锁通常通过fcntl函数实现,下面是与读写锁相关的宏。

F_GETLK 表示当前是否加文件锁及锁的属性。
F_SETLK 设置锁的属性
F_SETLKW 阻塞方式设置锁的属性
F_RDLCK 读取锁
F_WRLCK 写入锁
F_UNLCK 解锁

struct flock是文件锁的具体结构:

struct flock{
    short l_type;      //锁的类型
    off_t l_start;     //相对l_whence的偏移量
    short l_whence;    //基准位置
    off_t l_len;       //加锁区域长度
    pid_t l_pid;       //加锁的进程号
}

可以看到文件锁的粒度是可以由应用程序控制的,最小粒度为字节。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值