Fix*_*xee 47 filesystems multiprocessing seek
我正在构建一个系统,其中多个从属进程通过unix域套接字进行通信,并且它们同时写入同一文件.我从未研究过文件系统或这个特定的文件系统(ext4),但感觉这里可能存在一些危险.
每个进程写入输出文件的不相交子集(即,正在写入的块中没有重叠).例如,P1仅写入文件的前50%,P2仅写入第二个50%.或者P1在P2写入偶数块时可能只写入奇数块.
拥有P1和P2(在不同的线程上同时运行)写入同一文件而不使用任何锁定是否安全?换句话说,文件系统是否隐式强加了某种锁定?
注意:遗憾的是,我不能随意输出多个文件并在以后加入.
注意:自发布此问题以来,我的阅读与下面仅发布的答案不一致.我读过的所有内容都表明我想做的事情很好,而下面的受访者坚持认为我所做的是不安全的,但我无法辨别所描述的危险.
jan*_*neb 29
如果您正在使用POSIX"原始"IO系统调用,例如read(),write(),lseek()等,那么您所做的事情似乎完全没问题.
如果你使用C stdio(fread(),fwrite()和朋友)或其他一些有自己的用户空间缓冲的语言运行库,那么"Tilo"的答案是相关的,因为缓冲,这是一些在您无法控制的范围内,不同的进程可能会覆盖彼此的数据.
Wrt OS锁定,而POSIX声明写入或读取小于PIPE_BUF的大小是某些特殊文件(管道和FIFO)的原子,对常规文件没有这样的保证.在实践中,我认为页面中的IO很可能是原子的,但是没有这样的保证.操作系统仅在内部锁定到保护其自身内部数据结构所必需的程度.可以使用文件锁或其他一些进程间通信机制来序列化对文件的访问.但是,所有这些只与您有几个进程在文件的同一区域执行IO有关.在您的情况下,由于您的进程正在执行IO以分离文件的各个部分,这些都不重要,您应该没问题.
Til*_*ilo 27
不,一般来说这样做是不安全的!
您需要为每个进程获取一个独占的写锁定 - 这意味着所有其他进程必须等待一个进程写入文件...您拥有的I/O密集型进程越多,等待时间就越长.
最好每个进程有一个输出文件,并在行的开头用时间戳和进程标识符格式化这些文件,以便以后可以脱机合并和排序这些输出文件.
提示:检查Web服务器日志文件的文件格式 - 这些是使用行开头的时间戳完成的,因此可以稍后对它们进行组合和排序.
编辑
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或Mutexes来同步进程,并确保其中只有一个可以一次写入文件.
正如我之前提到的,为每个进程提供一个输出文件可能更快,更简单,更直接,然后在需要时(离线)组合这些文件.例如,某些Web服务器使用此方法,需要从多个线程记录多个文件 - 并且需要确保不同的线程都是高性能的(例如,不必在文件上等待彼此锁).
这是一个相关的帖子:(检查Mark Byer的答案!接受的答案不正确/相关.)
编辑2:
在评论中,您说要将不同进程的固定大小的二进制数据块写入同一文件.
只有在块大小与系统文件缓冲区大小完全相同的情况下,这才有效!
确保固定块长度与系统的文件缓冲区大小完全相同.否则,您将遇到与未完成的行相同的情况.例如,如果您使用16k块,并且系统使用4k块,那么通常您会看到文件中的4k块看似随机顺序 - 无法保证您始终会看到来自同一进程的4个块