61

我正在构建一个系统,其中多个从属进程通过 unix 域套接字进行通信,并且它们同时写入同一个文件。我从未研究过文件系统或这个特定的文件系统(ext4),但感觉这里可能存在一些危险。

每个进程写入输出文件的不相交子集(即,正在写入的块中没有重叠)。例如,P1仅写入文件的前 50%,P2仅写入后 50%。或者可能P1只写入奇数块而P2写入偶数块。

在不使用任何锁定的情况下让P1P2(在不同的线程上同时运行)写入同一个文件是否安全?换句话说,文件系统是否隐式地强加了某种锁定?

注意:很遗憾,我不能随意输出多个文件并在以后加入它们。

注意:自发布此问题以来,我的阅读内容与下面唯一发布的答案不一致。我读到的所有内容都表明我想做的事情很好,而下面的受访者坚持认为我所做的事情是不安全的,但我无法辨别所描述的危险。

4

2 回答 2

37

如果您使用的是 POSIX“原始”IO 系统调用,例如 read()、write()、lseek() 等,那么您所做的似乎完全没问题。

如果您使用 C stdio(fread()、fwrite() 和朋友)或其他一些具有自己的用户空间缓冲的语言运行时库,那么“Tilo”的答案是相关的,因为缓冲,这对一些在您无法控制的范围内,不同的进程可能会覆盖彼此的数据。

Wrt OS 锁定,而 POSIX 声明写入或读取小于 PIPE_BUF 的大小对于某些特殊文件(管道和 FIFO)是原子的,但对于常规文件没有这样的保证。在实践中,我认为页面内的 IO 很可能是原子的,但没有这样的保证。操作系统仅在保护其内部数据结构所需的范围内进行内部锁定。可以使用文件锁或其他一些进程间通信机制来序列化对文件的访问。但是,所有这些仅与您有多个进程对文件的同一区域执行 IO 相关。在您的情况下,由于您的进程正在对文件的不相交部分进行 IO,因此这些都不重要,您应该没问题。

于 2011-10-25T16:47:19.497 回答
33

不,通常这样做是不安全的!

您需要为每个进程获得一个独占写入锁——这意味着所有其他进程将不得不等待一个进程正在写入文件。您拥有的 I/O 密集型进程越多,等待时间越长。

最好每个进程有一个输出文件,并在行首使用时间戳和进程标识符格式化这些文件,以便以后可以离线合并和排序这些输出文件。

提示:检查网络服务器日志文件的文件格式——这些都是在行首加上时间戳,以便以后可以组合和排序。


编辑

UNIX 进程在打开文件时使用一定/固定的缓冲区大小(例如 4096 字节),以在磁盘上的文件之间传输数据。一旦写入缓冲区已满,该进程会将其刷新到磁盘 - 这意味着:它将完整的完整缓冲区写入磁盘!请注意,这是在缓冲区已满时发生的!-- 不是在有行尾时!这意味着即使对于将面向行的文本数据写入文件的单个进程,这些行通常在刷新缓冲区时在中间的某处被剪切。只有在最后,当文件在写入后关闭时,您才能假设文件包含完整的行!

因此,取决于您的进程何时决定刷新其缓冲区,它们会在不同时间写入文件——例如,顺序不确定/不可预测当缓冲区刷新到文件时,您不能假设它只会写入完整的行—— - 例如,它通常会写入部分行,因此如果多个进程在没有同步的情况下刷新它们的缓冲区,则会弄乱输出。

查看维基百科上的这篇文章:http ://en.wikipedia.org/wiki/File_locking#File_locking_in_UNIX

引用:

Unix 操作系统(包括 Linux 和 Apple 的 Mac OS X,有时称为 Darwin)通常不会自动锁定打开的文件或正在运行的程序。几种文件锁定机制在不同风格的 Unix 中可用,并且许多操作系统支持不止一种以实现兼容性。两种最常见的机制是 fcntl(2) 和 flock(2)。第三种这样的机制是 lockf(3),它可以是独立的,也可以使用前两个原语中的任何一个来实现。

您应该使用flock 或Mutex来同步进程,并确保一次只有其中一个可以写入文件。

正如我之前提到的,为每个进程创建一个输出文件,然后在需要时合并这些文件(离线)可能更快、更容易、更直接。例如,一些网络服务器使用这种方法,它们需要从多个线程登录到多个文件——并且需要确保不同的线程都是高性能的(例如,不必在文件上相互等待锁)。


这是一个相关的帖子:(检查 Mark Byer 的答案!接受的答案不正确/不相关。)

使用 >> 将多个并行进程的输出通过管道传输到一个文件是否安全?


编辑2:

在评论中你说你想将不同进程的固定大小的二进制数据块写入同一个文件。

只有在您的块大小正好是系统文件缓冲区大小的情况下,这才有效!

确保您的固定块长度正好是系统的文件缓冲区大小。否则,您将遇到与未完成的行相同的情况。例如,如果您使用 16k 块,而系统使用 4k 块,那么通常您会在文件中以看似随机的顺序看到 4k 块——不能保证您总是会从同一个进程中连续看到 4 个块

于 2011-10-20T22:23:49.160 回答