这是一个以UNIX为中心的后续问题my previous question here。
我想知道一个进程打开的文件描述符是否可以安全地用在分叉进程中。
我通过同时运行几百个进程来运行一些测试,所有进程都连续写入同一个文件描述符。我发现了:
fwrite()
调用最多为8192个字节时,所有调用都完全序列化,文件正常。fwrite()
调用超过8192个字节时,字符串被分成8192个字节块,这些块随机写入文件,最终会损坏。我尝试使用flock()
,但没有成功,因为每个进程都试图锁定/解锁相同的文件描述符,这是没有意义的。结果是一样的。
有没有办法在所有进程之间安全地共享文件描述符,并使所有fwrite()
调用正确序列化?
答案 0 :(得分:3)
首先需要注意的是stdio缓冲区。因为您使用的是stdio(fwrite()
)而不是系统调用directlr(write()
),所以您不知道数据何时会实际刷新到文件中。要绕过此问题,每次释放锁之前,都必须在关键部分内刷新stdio缓冲区:
take the lock
fwrite(foo, ...);
fflush(thefile);
release the lock
...或者您可以直接切换为使用write()
。
现在,关于主要问题:如何锁定文件,以便一次只有一个进程可以独占访问该文件。
您可能会也可能无法使用flock()
。它取决于不同进程如何获取同一文件的文件描述符。 flock()
锁与打开的文件表条目相关联。因为fork()
和dup()
创建了引用相同文件表条目的新文件描述符,所以它们是flock()
视角下的同一对象,因此您无法使用{{ 1}}在这种情况下。另一方面,如果每个流程都直接使用flock()
打开了自己的文件副本,那么您可以使用open()
。
flock()
- 样式锁定不会遇到此问题(它会遇到不同类型的问题!)。 fcntl()
锁是按进程进行的,因此进程如何将文件描述符获取到同一文件并不重要。
所以我建议您尝试使用fcntl()
- 样式锁定:
fcntl()
答案 1 :(得分:2)
您使用文件描述符的方式非常安全。写入不同步,因此输出可能不是您所期望的,但没有什么“不安全”。如果您问“如何将写入同步到公共文件描述符”,那么答案显而易见:使用同步机制。在您描述在多个进程之间共享一个文件描述符的情况下,最简单的方法是在第二个管道上传递令牌。拥有一个在所有进程之间共享的管道,并在其中写入一个字符。当进程想要写入第一个fd时,它会尝试从管道中读取一个字符。读取成功后,继续写入(确保刷新),然后将字符写回管道。当任何进程处于临界区时(即,它已读取但尚未写入令牌),任何其他进程将阻止读取,直到另一个进程完成其写入,只要您不忘记刷新!这是一个相当昂贵的操作,因为它要求每个进程保持打开两个额外的文件描述符,并且可用文件描述符数量的上限相当低,通常大约为1024,但它通常非常有效。