完全に書き込まれる前に、このファイルを探しに行く可能性のある他のプロセスが読み取りを開始しないように、作成時に読み取りに対してロックされるファイルを作成する必要があります。
作成してロックできることはわかっていますが、競合状態になる可能性があるのではないかと心配しています。
それとも私はここで何も心配していませんか?ファイルを書き込み用に開いてから、別のプロセスで読み取り用に開いた場合、書き込みプロセスがファイルを閉じるまで、読み取りプロセスは EOF を認識しませんか?
完全に書き込まれる前に、このファイルを探しに行く可能性のある他のプロセスが読み取りを開始しないように、作成時に読み取りに対してロックされるファイルを作成する必要があります。
作成してロックできることはわかっていますが、競合状態になる可能性があるのではないかと心配しています。
それとも私はここで何も心配していませんか?ファイルを書き込み用に開いてから、別のプロセスで読み取り用に開いた場合、書き込みプロセスがファイルを閉じるまで、読み取りプロセスは EOF を認識しませんか?
との競合状態がありますが>
、>>
を使用して回避できます+<
。
# >
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
この問題を回避するための一般的な戦略は、ライターを雇うことです
rename
ファイルが完成したときにリーダーが監視するディレクトリにファイルを追加します。rename
はアトミックアクションであるため、ファイルはリーダーが監視するディレクトリに完全に形成された状態で表示されます。これにはライターの協力が必要ですが、最善の解決策はそうなります。
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
加工を除く。
(FWIW、半分書き込まれたファイルを読み取ると、EOF 状態になります。)
これは、お使いのオペレーティング システムでサポートされているか、サポートされていません。もしそうなら、それは簡単で簡単です。
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: $!";