web-dev-qa-db-ja.com

Unixでの移動操作はアトミックですか?

2つのプロセスP1とP2があり、それらが共有ファイルFoo.txtにアクセスするとします。

P2がFoo.txtから読み取っているとします。 P2が読み取っているときにP1がFoo.txtに書き込みをしたくありません。

そのため、P1をFoo.tmpに書き込み、最後のステップとして、Foo.tmpの名前をFoo.txtに変更できると思いました。私のプログラミング言語はJavaです

だから私の質問は、これはP2がFoo.txtから正しいデータを読み取ることを保証しますか? P2がファイルの読み取りを完了すると、名前変更操作がコミットされますか?

[〜#〜]編集[〜#〜]

このシナリオを次のように再現しようとしました。

私のP1コードは次のようなものです:

File tempFile = new File(path1);
File realFile = new File(path2);
BufferedWriter writer = new BufferedWriter(new FileWriter(tempFile));
for(int i=0;i<10000;i++)
    writer.write("Hello World\n");
writer.flush();
writer.close();
tempFile.renameTo(realFile);

そして私のP2コードは:

BufferedReader br = new BufferedReader(new FileReader(file)); 
String line = null;
while(true) {
  while((line=br.readLine())!=null){
      System.out.println(line);
      Thread.sleep(1000);
  }
  br.close();
}

私のサンプル共有ファイル:

Test Input
Test Input
Test Input   

P1とP2をほぼ同時に開始しています(P2が最初に開始します)。

したがって、私の理解によれば、P1が新しいFoo.txtを書き込んだとしても、P2はすでにそれを読み取っているので、BufferedReaderをFoo.txtに再度開くまで、古いFoo.txtコンテンツを読み取る必要があります。

しかし、実際に起こることは、入力から予想されるように、P2がTest Inputを3回読み取ることですが、その後、P1によって書き込まれた新しいコンテンツを読み取ります。

P2からの出力:

Test Input
Test Input
Test Input 
Hello World
Hello World
Hello World
 .
 .
 .

そのため、正常に機能しません。このシナリオのテストは間違っていますか?何か足りないものがあるような気がします。

22
Chaos

UNIXのrename操作はアトミックです(rename(2)を参照)。 UNIXのmvコマンドは、ソースパスとターゲットパスが同じ物理デバイス上にある場合、renameを使用します。ターゲットパスが別のデバイス上にある場合、名前の変更は失敗し、mvはファイルをコピーします(これはアトミックではありません)。

ターゲットファイルパスが存在する場合、renameはそれをファイルシステムからアトミックに削除し、新しいファイルに置き換えます。ファイルは、参照カウントがゼロになるまで実際には削除されないため、別のプロセスが現在ファイルを読み取っている場合は、古いファイルを読み取り続けます。すべてのプロセスが古いファイルを閉じると、その参照カウントはゼロになり、ファイルストレージスペースが再利用されます。

36
Chris Dodd

FileChannel.lockを使用してみませんか?

ここに例があります:

http://examples.javacodegeeks.com/core-Java/nio/filelock/create-shared-file-lock-on-file/

5
Kent
  1. 同じデバイスで実行した場合、move(rename)はアトミックです。 (デバイス=同じディスク/パーティション)
  2. Foo.txtが終了した場合、Foo.tmpFoo.txtに移動すると失敗する可能性が高くなります。 (ただし、最初にFoo.txtを削除してから移動すると、機能するはずです)。何が起こるかというと、すべてのファイルハンドラーが閉じられるまで、ファイルは物理的に削除されません(そのファイルを使用するプロセスはありません)。また、Foo.tmpからFoo.txtを残した後、2つのFoo.txtファイルが作成されます。削除されたがまだメモリ内で開かれているもの(基本的に、そのファイルはディスク上に参照を持っていません)と実際にディスク上にあるもの。
  3. ただし、移動後、2番目のプロセスでファイルを再度開く必要があります。

#1と同じページにいるかどうか教えてください。

3
Claudiu