简体   繁体   English

在FreeBsd和Linux上使用O_APPEND打开文件看起来不像是原子操作?

[英]Open file with O_APPEND on FreeBsd and Linux doesn't look like an atomic operation?

#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#define BUFSIZE 1024*1024*100
#define FILE_MODE       (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
int main()
{
    pid_t pid;
    int pfd = open("data.txt", O_CREAT|O_RDWR|O_TRUNC|O_APPEND, FILE_MODE);
    if ((pid = fork()) < 0)
    {
    printf("errr fork\n");
    exit(0);
    } else if (pid == 0)
    {
        int cfd = open("data.txt", O_CREAT|O_RDWR|O_TRUNC|O_APPEND, FILE_MODE);
        for (int i = 0; i < 1000000; ++i)
            if (write(cfd, "child\n", 6) == -1)
        {
        printf("err in child\n");
        exit(0);
        }

        exit(0);
    }
    for (int i = 0; i < 1000000; ++i)
        if (write(pfd, "parent\n", 7) == -1)
    {
        printf("error in parent\n");
        exit(0);
    }
    return 0;
}

Test environment 1: 测试环境1:

uname -a 优名
FreeBSD freebsd 10.0-RELEASE-p12 FreeBSD 10.0-RELEASE-p12 #0: Tue Nov 4 05:07:17 UTC 2014 root@amd64-builder.daemonology.net:/usr/obj/usr/src/sys/GENERIC amd64 FreeBSD freebsd 10.0-RELEASE-p12 FreeBSD 10.0-RELEASE-p12#0:星期二11月4日05:07:17 UTC 2014 root@amd64-builder.daemonology.net:/ usr / obj / usr / src / sys / GENERIC amd64

clang -v lang -v
FreeBSD clang version 3.3 (tags/RELEASE_33/final 183502) 20130610 Target: x86_64-unknown-freebsd10.0 Thread model: posix FreeBSD clang版本3.3(tags / RELEASE_33 / final 183502)20130610目标:x86_64-unknown-freebsd10.0线程模型:posix

Test environment 2: 测试环境2:

uname -a 优名
Linux debian 3.2.0-4-amd64 #1 SMP Debian 3.2.63-2+deb7u1 x86_64 GNU/Linux Linux debian 3.2.0-4-amd64#1 SMP Debian 3.2.63-2 + deb7u1 x86_64 GNU / Linux

gcc --version gcc --version
gcc (Debian 4.7.2-5) 4.7.2 Copyright (C) 2012 Free Software Foundation, Inc. This is free software; gcc(Debian 4.7.2-5)4.7.2版权所有(C)2012自由软件基金会,公司。 see the source for copying conditions. 请参阅复制条件的来源。 There is NO warranty; 没有保修; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 甚至不是出于适销性或针对特定目的的适用性。

Some lines lost 有些线丢了

$ sort data.txt | uniq -c
1000000 child
982937 parent

O_APPEND doesn't seem to work as the man page said it should. O_APPEND似乎没有按照手册页中的说明工作。

Can anyone give me more information about this? 谁能给我更多有关此的信息?

The trouble is that when the child opens the file, it truncates it, losing the data that the parent has already written to the file, leaving the parent with a short count. 问题在于,当子级打开文件时,它将被截断,丢失了父级已写入文件的数据,从而使父级的计数减少了。 It is likely that it will always be the parent with the short count because the child has to open the file a second time, and file opening is an expensive operation. 由于孩子必须第二次打开文件,并且文件打开是一项昂贵的操作,因此它可能永远是计数少的父级。 If the first open was moved so it was only in the parent, the timing would be different; 如果将第一个打开位置移动到只有父打开位置,则时间会有所不同; it's possible that the child would sometimes have fewer entries. 有时孩子的条目可能会更少。

Modified code: 修改后的代码:

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

#define FILE_MODE       (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)

int main(void)
{
    pid_t pid;
    int pfd = open("data.txt", O_CREAT | O_RDWR | O_TRUNC | O_APPEND, FILE_MODE);
    if ((pid = fork()) < 0)
    {
        printf("errr fork\n");
        exit(0);
    }
    else if (pid == 0)
    {
        int cfd = open("data.txt", O_CREAT | O_RDWR | O_TRUNC | O_APPEND, FILE_MODE);
        for (int i = 0; i < 1000000; ++i)
        {
            char buffer[32];
            snprintf(buffer, sizeof(buffer), "child%07d\n", i);
            if (write(cfd, buffer, strlen(buffer)) == -1)
            {
                printf("err in child\n");
                exit(0);
            }
        }
    }
    else
    {
        for (int i = 0; i < 1000000; ++i)
        {
            char buffer[32];
            snprintf(buffer, sizeof(buffer), "parent%07d\n", i);
            if (write(pfd, buffer, strlen(buffer)) == -1)
            {
                printf("error in parent\n");
                exit(0);
            }
        }
    }
    return 0;
}

One time when I ran it, the output started: 一次运行它时,输出开始:

parent0000052
parent0000053
parent0000054
parent0000055
parent0000056
parent0000057
parent0000058
parent0000059
parent0000060
parent0000061
parent0000062
parent0000063
parent0000064
child0000000
parent0000065
child0000001
parent0000066
child0000002
parent0000067

So, the parent had executed 52 writes before the child truncated the file (0..51). 因此,父级在子级截断文件(0..51)之前已执行52次写入。 The counts agree: 计数同意:

$ grep -o -E 'child|parent' data.txt | sort | uniq -c
1000000 child
999948 parent
$

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

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