linux系统编程 您所在的位置:网站首页 多进程读写同一个文件 linux系统编程

linux系统编程

2024-07-02 17:33| 来源: 网络整理| 查看: 265

1. 写文件的互斥

不论是 多线程,多进程,同时写一个文件,在数据写入 页缓存时,都是原子的, 如进程a 写入 "aaaa" 进程b 写入 "bbbb",则内核可能会将 "aaaa" 完整的写入 页缓存,在将完整的 "bbbb" 写入页缓存, 不会出现 "aa" "bbbb" "aa" 的情况。

相关代码如下 对于普通文件,write() 底层会调用 aio_write()

ssize_t generic_file_aio_write(struct kiocb *iocb, const struct iovec *iov, unsigned long nr_segs, loff_t pos) { struct file *file = iocb->ki_filp; struct inode *inode = file->f_mapping->host; ssize_t ret; BUG_ON(iocb->ki_pos != pos); mutex_lock(&inode->i_mutex); ret = __generic_file_aio_write(iocb, iov, nr_segs, &iocb->ki_pos); mutex_unlock(&inode->i_mutex); if (ret > 0) { ssize_t err; err = generic_write_sync(file, pos, ret); if (err < 0 && ret > 0) ret = err; } return ret; } 2. 导致冲突的是 f_pos

aio_write() 的参数 pos,是从 f_pos来的,也就说,在 真正的原子写 前,确定的 pos,则pos没有原子性, 若 两个进程 写同个文件,由于 两个 进程的 struct file不同,所以 f_pos不同,导致内容覆盖。 若 父子进程 写同个文件,由于 struct file 相同,所以 f_pos 相同,但是 pos 的设置没有原子性,所以 也可能内容覆盖。 若 多线程 写同个文件,情况同上。

ksys_write() 中 获得 pos 和 设置 pos 没有上锁,所以 A线程获得pos为0,B线程获得pos为0,A线程写"aa",设置pos为2,B线程的pos仍然为0,导致A的数据被覆盖。

static inline loff_t file_pos_read(struct file *file) { return file->f_pos; } static inline void file_pos_write(struct file *file, loff_t pos) { file->f_pos = pos; } ssize_t ksys_write(unsigned int fd, const char __user *buf, size_t count) { struct fd f = fdget_pos(fd); ssize_t ret = -EBADF; if (f.file) { loff_t pos = file_pos_read(f.file); ret = vfs_write(f.file, buf, count, &pos); if (ret >= 0) file_pos_write(f.file, pos); fdput_pos(f); } return ret; } SYSCALL_DEFINE3(write, unsigned int, fd, const char __user *, buf, size_t, count) { return ksys_write(fd, buf, count); } 3. 用O_APPEND解决冲突

使用O_APPEND时,generic_file_aio_write()使用的pos在用的时候根据 inode大小 获得的, 所以 使用 O_APPEND 时,无论是 多线程,多进程 都能保证同步。

但是 若文件是 pipe,则写大小必须小于 PIPE_SIZE 才能保证写的完整性

4. 启发

由于 多线程 write() 最后会成 串行 write,所以使用mmap 直接 并发写页缓存更合适

5. 标准IO

标准IO能保证原子性,只要 对一个 FILE 写,则不会有冲突



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有