繁体   English   中英

为什么我的多进程写程序不会触发并发冲突?

[英]Why doesn't my multi-process writing program trigger concurrent conflict?

我试图通过让多个进程写入同一个文件来触发一些并发冲突,但不能:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <sys/wait.h>

void concurrent_write()
{
    int create_fd = open("bar.txt", O_CREAT | O_TRUNC, 0644);
    close(create_fd);
    int repeat = 20;
    int num = 4;

    for (int process = 0; process < num; process++)
    {
        int rc = fork();
        if (rc == 0)
        {
            // child
            int write_fd = open("bar.txt", O_WRONLY | O_APPEND, 0644);
            for (int idx = 0; idx < repeat; idx++)
            {
                sleep(1);
                write(write_fd, "child writing\n", strlen("child writing\n"));
            }
            close(write_fd);

            exit(0);
        }
    }

    for (int process = 0; process < num; process++)
    {
        wait(NULL);
        // wait for all children to exits
    }

    printf("write to `bar.txt`\n%d lines written by %d process\n", repeat * num, num);

    printf("wc:");
    if (fork() == 0)
    {
        // child
        char *args[3];
        args[0] = strdup("wc");
        args[1] = strdup("bar.txt");
        args[2] = NULL;
        execvp(args[0], args);
    }
}

int main(int argc, char *argv[])
{
    concurrent_write();

    return 0;
}

这个程序 fork #num孩子,然后让他们都将#repeat行写入一个文件。 但是每次(但是我更改#repeat#num )我都得到了相同的结果,即bar.txt (输出文件)的长度与总写入行数相匹配。 为什么没有触发并发冲突?

写入文件可以分为两步过程:

  1. 找到你想写的地方。
  2. 将数据写入文件。

您打开一个带有标志O_APPEND的文件,它确保两步过程是原子的。 因此,您始终可以按照您设置的计数找到文件的行数。

请参阅open(2)手册页

O_APPEND

该文件以 append 模式打开。 在每次 write(2) 之前,文件偏移量位于文件末尾,就像使用 lseek(2) 一样。 文件偏移量的修改和写入操作作为单个原子步骤执行。

本质上, O_APPEND的主要设计特点之一就是防止您提到的那种“并发冲突”。 典型示例是多个进程必须写入的日志文件。 使用O_APPEND确保它们的消息不会相互覆盖。

此外,单个write调用写入的所有数据都是原子写入的,因此只要您的write("child writing\n")成功写入其所有字节(对于常规文件通常会这样),它们就不会与任何其他此类消息的字节。

首先,带有O_APPEND标志的write()调用应该是原子的。 根据 POSIX write()

如果设置了文件状态标志的O_APPEND标志,则文件偏移量应在每次写入之前设置为文件末尾,并且在更改文件偏移量和写入操作之间不会发生任何干预文件修改操作。

但是,当有多个线程或进程对同一个文件进行并行write()调用时,这还不够——这并不能保证并行write()调用是原子的。

POSIX 确实保证并行write()调用也是原子的

在 POSIX.1-2017 中指定的效果中,当它们对常规文件或符号链接进行操作时,以下所有函数相对于彼此应该是原子的:

 ... write()...

另见文件 append 在 UNIX 中是原子的吗?

不过要小心。 阅读该问题及其答案表明 Linux 文件系统(例如ext3 )一旦通过相对较小的操作,或者可能跨越页面和/或文件系统扇区边界,则不符合 POSIX 标准。 我怀疑 XFS 和 ZFS 会更好地支持write()原子性,因为它们的起源。

这些都不适用于 Windows。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM