多处理和文件操作

Multi-processing and file operations?

本文关键字:操作 文件 处理      更新时间:2023-10-16

在基于windows的操作系统中,假设有几个不同的进程可以通过使用fopen/fopen_s/fwrite等频繁地读取和/或写入文件,在这种情况下,我需要考虑数据竞争吗?或者操作系统可以自动处理这一问题,以确保文件在任何给定时间只能由单个进程打开/更新,而其余的打开尝试将失败?在这个问题上,基于linux的操作系统又如何呢?

在Windows中,这取决于打开文件的方式。

参见在OpenFile的情况下的uStyle参数和在CreateFile的情况下dwShareMode参数的一些可能值。

请注意,OpenFile有点不推荐使用,因此最好使用CreateFile

您必须注意不要同时从多个线程打开同一个文件,因为完全有可能多次打开该文件,操作系统可能会也可能不会执行您的预期,根据你打开文件的模式,例如,如果你创建了一个新文件,它肯定会创建两个不同的文件(其中一个在关闭时会消失,因为它被另一个线程删除了,太好了,嗯?)。规则非常复杂,最糟糕的是,如果你不格外小心,你会得到"同一个文件的混合输出"——所以两个线程中的行甚至部分行会混合。

即使操作系统阻止您两次打开同一个文件,您仍然需要处理"FILE *NULL的形式返回"的后果。那你干什么?回去再试一次,或者失败,或者?

我不确定我能不能就如何解决这个问题提出一个好的建议,因为你没有很好地描述你对这些文件所做的事情。脑海中浮现出一些不同的东西:

  1. 保留一个文件名的"寄存器",并为每个必须持有才能打开文件的文件保留一个互斥锁
  2. 使用一个"文件线程"来读取/写入文件上的数据,只需排队"我想把这些东西写到文件aa.txt",然后让工作人员边写边写
  3. 使用较低级别的文件系统调用,并使用对文件的"独占"访问,在发生冲突时会有某种"后退"行为

我相信还有几十种其他方法可以解决这个问题,这实际上取决于你想做什么。

也许吧。如果你谈论的是不同的过程(而不是线程),适用于线程不适用。但是(没有区别在Unix和Windows之间):

  • 任何单个write/WriteFile操作都将是原子操作。(我是对Windows不是百分之百确定,但我无法想象否则。)但是,如果您使用iostream或旧版本FILE*函数,您无法直接控制进行操作。通常,只有当流的缓冲区已满。您需要确保缓冲区足够大,并在每次输出后显式刷新。(如果你输出的行长度合理,比如说80行最多字符,可以肯定的是缓冲区将保持完整的线路。在这种情况下,只需使用std::endl终止iostreams中的行;对于C型函数,你必须先打电话给setvbuf( stream, NULL, _IOLBF, 0 )第一输出。

  • 这个过程中的每个打开的文件都有自己的位置在文件中写入,以及它自己对文件末尾在哪里的想法。如果您希望所有写入都转到文件末尾,则需要用C++中的std::ios_base::app或C中的"a"打开它std::ios_base::out/"w"是不够的。(当然,只有std::ios_base::out或"w",文件将打开时被截断。有几个不同的过程截断文件可能会导致数据丢失。)

  • 当读取其他进程正在写入的文件时:当当到达文件末尾时,流或FILE会出错状态,并且不会尝试进一步读取,即使其他进程正在附加数据。在C中,clearerr应该(我认为)撤消这一点,但尚不清楚接下来会发生什么;在C++中,清除流中的错误并不一定意味着进一步读取也不会立即遇到文件末尾。在两者中在这种情况下,最安全的办法是记住你在每一次之前的位置读取,如果读取失败,请关闭文件,然后再重新打开找到你所在的地方,然后从那里开始阅读。

  • 随机访问,在文件末尾以外的位置写入,将同样有效,只要所有的写入都是原子的(见上文);你应该始终保持一致的状态。如果你写什么取决于然而,根据你所读的内容和其他过程类似的情况下,您需要文件锁定,而不是在iostream/FILE*级别可用。