【问题标题】:Is there a way to create a file that is locked at the point of creation, in Perl?有没有办法在 Perl 中创建一个在创建时被锁定的文件?
【发布时间】:2011-06-17 14:27:31
【问题描述】:

我需要在创建时创建一个锁定读取的文件,以便其他可能寻找该文件的进程在完全写入之前不会开始读取它。

我知道我可以创建并然后锁定它,但我担心这会让我面临竞争条件。

或者我在这里什么都不担心吗?如果我打开一个文件进行写入,然后用另一个进程打开它进行读取,那么在写入进程关闭文件之前,读取进程是否永远不会看到 EOF?

【问题讨论】:

标签: perl file-io file-locking


【解决方案1】:

>>> 存在竞争条件,但可以使用 +< 规避它。

# >
open(my $fh, '+<', $qfn) or die $!;
flock($fh, LOCK_EX) or die $!;
truncate($fh, 0) or die $!;
...

# >>
open(my $fh, '+<', $qfn) or die $!;
flock($fh, LOCK_EX) or die $!;
seek($fh, 0, SEEK_END) or die $!;
...

在您描述的场景中也存在竞争条件。

Writer                       Reader
=========================    =========================
- opens file
                             - opens file
                             - locks file
                             - obtains lock on file
- locks file [blocks]        - reads the file [empty]
                             - closes and unlocks file
- obtains lock on file
- writes to file
- writes to file
- closes and unlocks file

避免这个问题的一个常见策略是让作家

  1. 在临时目录中创建文件,然后
  2. rename 将文件放入阅读器在文件完成时监视的目录中。

rename 是一个原子操作,因此文件将在阅读器监视的目录中显示为完整格式。这需要作者的合作,但最好的解决方案会。

【讨论】:

  • 当 Read 在 Writer 打开(并因此创建)和锁定文件之间打开文件时,就会出现竞争条件。
  • @Dancrumb,当然!不过,我描述的策略确实解决了这个问题。我已经相应地调整了我的帖子。
  • 太棒了……是的……这是一个很好的策略,可以避免在两个组件中管理锁的开销。
【解决方案2】:

在创建文件之前使用umask(0777)

文件系统中的文件条目将完全无法访问[*](即权限----------),即使您拥有的文件句柄仍然允许写入。

完成后chmod() 文件:

my $file = 'foo.txt';
my $umask = umask(0777);    # change the umask
open(OUT, '>', $file);      # create the file 
umask($umask);              # reset the umask
print OUT "testing\n";      # put stuff in your file
close(OUT);                 # finished with that...
chmod(0644, $file);         # change the permissions

注意:这实际上并不是严格意义上的“锁定”,操作系统会主动阻止对文件的访问。这是文件系统级别的“hack” - 如果您实际上无法打开文件,那么它就会被锁定。

[*] 除了root 进程。

(FWIW,读取半写文件导致 EOF 条件。)

【讨论】:

  • 从某种意义上说,这比 flock 在 unix 上提供的锁要好。这不仅仅是建议。
  • 谢谢@Alnitak。我通常使用 IO::File,我可以通过该调用设置权限......非常有义务
  • OP 的要求是延迟读者直到作者完成,这很困难。读者在准备好之前不能阻塞;他们必须继续尝试打开文件。
  • @ikegami 你昨天投了反对票,但在 2011 年你说它比咨询锁更好...:p
【解决方案3】:

您的操作系统要么支持此功能,要么不支持。如果是的话,那就简单了。

use Fcntl   qw( O_CREAT   O_EXCL   O_WRONLY   O_EXLOCK  );

$creat_flags = (O_CREAT | O_EXCL | O_WRONLY | O_EXLOCK );

sysopen(SOMEHANDLE, $somepath, $creat_flags, 0666)
    || die "$0: couldn't sysopen $somepath with flags $creat_flags: $!";

【讨论】:

    猜你喜欢
    • 2017-02-12
    • 1970-01-01
    • 1970-01-01
    • 2011-09-25
    • 1970-01-01
    • 2022-01-25
    • 1970-01-01
    • 1970-01-01
    • 2020-08-12
    相关资源
    最近更新 更多