记录一个暂时没有答案的race condition问题

今天遇到一个非常奇怪的race condition问题,是一段perl代码,进程互斥使用的是linux的文件锁,操作系统是rhel7.3.

这个函数是把一个文件中的一部分key=value改写,步骤是这样的:

1. 打开待读文件,上共享锁

2. 读文件内容到内存,关文件

3. 更改文件内容

4. 打开待写文件(和待读文件是一个文件),上排他锁

5. 删除文件内容,重新写入更改的文件内容,关闭文件


发现的问题是这个文件的原始内容有可能被删除掉,只剩下待写的内容。

直观的感觉是一个进程读到了一个空文件,然后只写了待写内容到文件中。

这个问题在测试机上出现过,调试中也出现过,但是没找到复现的方法。

但是从代码里看不出任何问题,看man page中的描述,一个文件不可能同时上共享锁和排它锁,所以在truncate的时候,不可能有其他的进程在读这个文件。

还没有找到原因。


linux flock man page: https://linux.die.net/man/2/flock


sub functionXXX {
    my (%params) = @_;

    my $setValue = 1;

    return undef if (!defined($params{KEY}) || !defined($params{FILE}) ||
                     !defined($params{VALUE}));
    my $outputString = "";

    # We will not need to take any action even if this command fails
    unless (! -f $params{FILE}) {
        open(my $readFh, "$params{FILE}") || return;
        flock( $readFh, 1 );
        my @lines = <$readFh>;
        close($readFh);
        foreach my $line (@lines) {
            chomp($line);
            if ($line =~ /\s*$params{KEY}\s*=.*/) {
                $outputString .= "$params{KEY} = $params{VALUE}\n";
                $setValue = 0;
            } else {
                $outputString .= "$line\n";
            }
        }
    }

    # This is a case where the file already exists but does not have the entry
    $outputString .= "$params{KEY} = $params{VALUE}\n" if ($setValue);

    if (trim($outputString) eq "") {
        $outputString = "$params{KEY} = $params{VALUE}";
    }
    unless (trim($outputString) eq "") {
        open(my $fh, "+>>$params{FILE}") || return;
        flock( $fh, 2 );
        seek( $fh, 0, 0 );
        truncate( $fh, 0 );
        print $fh $outputString;
        close($fh);
    }

}


你可能感兴趣的:(Linux)