2011-06-17 58 views
4

我需要在創建時創建一個鎖定爲讀取的文件,以便可能要查找此文件的其他進程在完全寫入之前不會開始讀取它。有沒有辦法在Perl中創建一個在創建時鎖定的文件?

我知道我可以創建並且然後鎖定它,但是我擔心這會讓我面對競爭條件。

我在這裏擔心什麼?如果我有一個打開文件的文件,然後打開它以便與另一個進程一起讀取,那麼在寫入進程關閉文件之前,讀取進程是否從不會看到EOF?

+0

http://perl.plover.com/yak/flock/samples/slide011.html – daxim

+0

@daxim這只是一個_advisory_鎖 - 它不會阻止流程,不遵循正常打開信號燈語義文件。 – Alnitak

回答

7

有與>>>的競爭條件,但它可以使用+<被規避。

# > 
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是一個原子操作,因此該文件將在讀者監視的目錄中完全形成。這需要作者的合作,但最好的解決方案會。

+0

@Dancrumb,我已添加到我的答案中。 – ikegami

+0

當Read在Writer打開(並因此創建)和鎖定文件之間打開文件時,就會出現競態條件。 – Dancrumb

+0

@Dancrumb,當然!不過,我描述的策略確實解決了這個問題。我相應地調整了我的帖子。 – ikegami

9

在創建文件之前使用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 

注意:這實際上不是嚴格意義上的,其中操作系統積極阻止對文件的訪問「鎖定」。這是一個文件系統級別的「黑客攻擊」 - 如果你實際上無法打開文件,那麼它就被鎖定了。

[*]除了root processesse。

(FWIW,閱讀半書面文件導致EOF條件。)

+1

從某種意義上說,這比unix上提供的「flock」更好。這不僅僅是諮詢。 – ikegami

+0

謝謝@Alnitak。我通常使用IO :: File,並且可以通過該調用設置權限......非常有必要 – Dancrumb

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: $!"; 
相關問題