微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

了解来自多个进程的并发文件写入

从这里: 文件在UNIX中追加primefaces

考虑多个进程打开同一个文件并追加到其中的情况。 O_APPEND保证寻找文件的结尾,然后开始写操作是primefaces的。 因此,多个进程可以追加到同一个文件中,只要每个写入大小<= PIPE_BUF,进程就不会覆盖其他进程的写入。

我写了一个testing程序,其中多个进程打开并写入同一个文件( write(2) )。 我确定每个写入大小是> PIPE_BUF(4k)。 我期待看到一个进程覆盖别人的数据的情况。 但那不会发生。 我testing了不同的写入大小。 这只是运气,还是有一个原因,为什么没有发生? 我的最终目标是了解多个进程追加到同一个文件是否需要协调其写入。

这是完整的程序。 每个进程创build一个int缓冲区,用它的rank填充所有值,打开一个文件并写入它。

C ++中是否有API来查找机器的环回IP地址?

在Windows上确定GPU制造商

如何防止MMAPcaching值?

如果进程崩溃,mmaped文件会发生什么?

Java:确保一个线程永远不会被上下文切换

规格:Opensuse 11.3 64位OpenMPI 1.4.3

编译为:mpicc -O3 test.c,运行如下:mpirun -np 8 ./a.out

#include <stdio.h> #include <stdlib.h> #include <mpi.h> #include <fcntl.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> int main(int argc,char** argv) { int rank,size,i,bufsize = 134217728,fd,status = 0,bytes_written,tmp_bytes_written; int* buf; char* filename = "/tmp/testfile.out"; MPI_Init(&argc,&argv); MPI_Comm_rank(MPI_COMM_WORLD,&rank); MPI_Comm_size(MPI_COMM_WORLD,&size); buf = (int*) malloc (bufsize * sizeof(int)); if(buf == NULL) { status = -1; perror("Could not malloc"); goto finalize; } for(i=0; i<bufsize; i++) buf[i] = rank; if(-1 == (fd = open(filename,O_APPEND|O_WRONLY,S_IWUSR))) { perror("Cant open file"); status = -1; goto end; exit(-1); } bytes_written = 0; if(bufsize != (tmp_bytes_written = write(fd,buf,bufsize))) { perror("Error during write"); printf("ret value: %dn",tmp_bytes_written); status = -1; goto close; } close: if(-1 == close(fd)) { perror("Error during close"); status = -1; } end: free(buf); finalize: MPI_Finalize(); return status; }

跟踪子/subprocess的进程ID?

如何在Windows 10中从高级pipe理员上下文启动非高级pipe理员进程?

什么是Win32_OperatingSystem的SerialNumber,它被认为是敏感信息?

“ls”命令在Linux / Unix中如何工作?

设备文件是由Linux中的特定文件系统还是虚拟文件系统实现的?

写入的原子性小于PIPE_BUF仅适用于管道和FIFO。 对于文件写入,POSIX说:

本卷的POSIX.1-2008没有指定从多个进程并发写入文件的行为。 应用程序应该使用某种形式的并发控制。

…这意味着你是自己的 – 不同的UNIX喜欢将给予不同的保证。

首先,Windows上的O_APPEND或等效的FILE_APPEND_DATA表示最大文件范围(文件“length”)的增量在并发写入器下是原子的 ,并且不是PIPE_BUF。 这是由POSIX保证的,Linux,FreeBSD,OS X和Windows都正确实施。 Samba也正确地实现了它,在v5之前的NFS并没有缺乏原子级连线的能力。 所以如果你用append-only来打开你的文件,除非涉及到NFS,否则在任何主要操作系统上 , 并发写入都不会相互撕裂 。

这并没有说明是否读取会看到一个撕裂的写作,并在POSIX说以下关于read()和write()到普通文件的原子性:

下面的所有函数在POSIX.1-2008规定的效果中,当它们在常规文件或符号链接上运行时,它们应该相互原子化… [许多函数] … read()… write( )…如果两个线程分别调用其中一个函数,则每个调用都将看到另一个调用的所有指定效果,或者都不会看到。 [资源]

写入可以被序列化为相对于其他读取和写入。 如果一个read()文件数据可以被证明(通过任何方法)在write()之后发生,那么它必须反映write(),即使这个调用是由不同的进程完成的。 [资源]

但相反:

本卷的POSIX.1-2008没有指定从多个进程并发写入文件的行为。 应用程序应该使用某种形式的并发控制。 [资源]

对这三个要求的安全解释表明,在同一文件中重叠范围的所有写入必须彼此相连并读取,使得撕碎的写入不会出现在读者面前。

一个不太安全,但仍然允许的解释可能是读写操作只能在同一进程内的线程之间进行串行化,而进程之间的写操作只能对只读进行序列化(即在线程之间存在顺序一致的I / O顺序一个进程,但是进程之间的I / O只是获取 – 释放)。

当然,仅仅因为标准要求这些语义并不意味着实现符合,但事实上FreeBSD与ZFS的行为完全相同,最近的Windows(10.0.14393)和NTFS的表现完美,而最近的ext4的Linux在O_DIRECT开启的情况下运行正常。 如果您想了解主要操作系统和文件系统如何符合标准的更多细节,请参阅此答案

这并不是运气,因为如果你深入内核,你可以证明,在你的特殊情况下,一个进程的write是不会发生的。 我假设:

您没有达到任何文件大小的限制

您没有填充您创建测试文件文件系统

文件一个普通的文件(不是套接字,管道或其他东西)

文件系统是本地的

该缓冲区不跨越多个虚拟内存映射(这个已知是真实的,因为它是malloc() ed,它把它放在堆上,它是连续的。

write()忙时,进程不会中断,发出信号或跟踪。

没有磁盘I / O错误,RAM故障或任何其他异常情况。

(也许别人)

您可能确实会发现,如果所有这些假设都成立,那么恰好您正在使用的操作系统的内核就会通过单个原子连续写入以下文件来实现一个write()系统调用

这并不意味着你可以指望这总是正确的。 你不知道什么时候可能不是真的:

该程序在不同的操作系统上运行

文件移动到一个NFS文件系统

进程在write()时获得信号, write()返回部分结果(比请求的字节更少)。 不知道POSIX是否真的允许这种情况发生,但我防守编程!

等等…

所以你的实验不能证明你可以在非交错写入。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。

相关推荐