【问题标题】:How can I synchronize -- make atomic -- writes on one file from from two processes?如何同步——使原子化——从两个进程写入一个文件?
【发布时间】:2011-08-01 08:42:39
【问题描述】:

我有两个进程,每个进程都在写入大缓冲区数据,我想控制这些进程对一个文件的写入同步。

进程 1 写入缓冲区 A 包括 (A1, A2, A3),进程 2 写入缓冲区 B 包括 (B1, B2, B3)。当我们使用write()系统调用将这些缓冲区写入磁盘到同一个文件(一次整个缓冲区:write(fd, A, sizeof(A)))时,文件架构如何?

  • 是这样的:A、B 还是 B、A?
  • 或者它可能是这样的:A1, A2, B1, A3, ...

我问这个是因为系统调用是原子的。如果我们正在写入的数据缓冲区太大会发生什么。是不是像普通磁盘文件的管道?

【问题讨论】:

    标签: c atomic


    【解决方案1】:

    如果您希望两个缓冲区的内容都存在,则必须打开设置了O_APPEND 标志的文件。附加标志在写入之前寻找文件的末尾。如果没有此设置,则两个进程可能会指向文件的相同或重叠区域,并且最后写入的人将覆盖其他人已写入的内容。

    每次调用write 都会写入请求的字节数。如果您的进程被信号中断,那么您可能会以部分写入结束——返回实际写入的字节数。无论您是否写入了所有字节,您都将写入文件的一个连续部分。您没有得到您提到的第二种可能性的交错效果(例如 A1,B1,A2,B2,...)。

    如果您只获得部分写入,则如何进行取决于您。您可以继续写入(从缓冲区开始偏移之前写入的字节数),也可以放弃其余的写入。只有这样,才有可能获得交错效果。

    如果在另一个进程写入之前完成一个写入的内容很重要,那么在尝试写入任何数据之前,您应该考虑锁定文件以进行独占写入访问(两个进程都必须检查)。

    【讨论】:

    • 所以我们没有任何信号并且启用了O_APPEND 我们应该有A,B 或B,A。我说的对吗?
    • @Majid - 是的,假设系统上没有任何东西打断你,你会得到 A、B 或 B,A,这取决于谁先走。
    • 值得注意的是,本地文件系统上的普通文件的写入永远不会中断。 NFS 有一个标志可以使它们可中断,但默认是关闭的。
    【解决方案2】:

    假设缓冲区大小相同,则结果将是 A 或 B,具体取决于最后调度的进程。

    write 系统调用是原子的,是的,这意味着结果将是 A 或 B,而不是两者的混合。

    假设文件中同时需要A和B,可以用O_APPEND打开文件;但请注意,这不适用于 NFS。

    另一个选项是每个进程跟踪它应该使用哪个文件偏移量,并使用 lseek() 或 pwrite()

    【讨论】:

      【解决方案3】:

      对于访问文件的程序,您肯定需要某种形式的同步,否则您最终会得到混乱的文件内容。 write 系统调用可能写入的字节数少于您请求的字节数,因此您的块 A1、A2 或 B1、B2 可能仅被部分写入。这可能会经常发生,也可能很少发生,具体取决于许多条件。如果它每周只发生一次,您将遇到一个很难检测到的错误。

      作为一种解决方案,您可以使用文件锁定(man 2 flockman fcntl 并搜索锁定)。另一种可能性是使用信号量 (man -k semaphore) 来同步您的程序写入,或其他形式的 IPC。

      【讨论】:

      • +1 文件锁定可能是一种可行的方法,因为一次性写下所有内容通常效率低下(或很难)。
      猜你喜欢
      • 1970-01-01
      • 2011-03-13
      • 1970-01-01
      • 1970-01-01
      • 2017-06-24
      • 1970-01-01
      • 1970-01-01
      • 2023-03-21
      • 1970-01-01
      相关资源
      最近更新 更多