32

プロセス間の名前付きミューテックスに flock() を使用しています (つまり、一部のプロセスは、一時ディレクトリ内の「some_name」という名前のファイルをロックすることによって実装される「some_name」のロックを保持することを決定できます。

lockfile = "/tmp/some_name.lock";
fd = open(lockfile, O_CREAT);
flock(fd, LOCK_EX);

do_something();

unlink(lockfile);
flock(fd, LOCK_UN);

ロック ファイルは、一時ディレクトリが何百ものファイルでいっぱいになるのを避けるために、ある時点で削除する必要があります。

ただし、このコードには明らかな競合状態があります。プロセス A、B、C の例:

A opens file
A locks file
B opens file
A unlinks file
A unlocks file
B locks file (B holds a lock on the deleted file)
C opens file (a new file one is created)
C locks file (two processes hold the same named mutex !)

この競合状態を導入することなく、ある時点でロック ファイルを削除する方法はありますか?

4

3 に答える 3

36

死んだ質問に答えたらごめんなさい:

ファイルをロックした後、その別のコピーを開き、両方のコピーを fstat して、次のように inode 番号を確認します。

lockfile = "/tmp/some_name.lock";

    while(1) {
        fd = open(lockfile, O_CREAT);
        flock(fd, LOCK_EX);

        fstat(fd, &st0);
        stat(lockfile, &st1);
        if(st0.st_ino == st1.st_ino) break;

        close(fd);
    }

    do_something();

    unlink(lockfile);
    flock(fd, LOCK_UN);

これにより、競合状態が回避されます。プログラムがファイル システム上にまだ存在するファイルをロックしている場合、残りのファイルを持つ他のすべてのプログラムが間違った inode 番号を持つことになるからです。

次のプロパティを使用して、ステートマシン モデルで実際に証明しました。

P_i がファイルシステムでロックされた記述子を持っている場合、他のプロセスはクリティカル セクションにありません。

P_i が右側の inode を持つ stat の後、またはクリティカル セクションにある場合、ファイルシステムでロックされた記述子があります。

于 2013-09-11T15:25:55.230 に答える
8
  1. Unix では、開いているファイルを削除することができます。ファイル記述子リストにあるすべてのプロセスが終了するまで、inode は保持されます。
  2. Unix では、リンク数がゼロになったときにチェックすることで、すべてのディレクトリからファイルが削除されたことを確認できます。

そのため、古いファイル パスと新しいファイル パスの ino 値を比較する代わりに、既に開いているファイルの nlink カウントを簡単に確認できます。これは単なる一時的なロック ファイルであり、実際のミューテックス リソースやデバイスではないと想定しています。

lockfile = "/tmp/some_name.lock";

for(int attempt; attempt < timeout; ++attempt) {
    int fd = open(lockfile, O_CREAT, 0444);
    int done = flock(fd, LOCK_EX | LOCK_NB);
    if (done != 0) { 
        close(fd);
        sleep(1);     // lock held by another proc
        continue;
    }
    struct stat st0;
    fstat(fd, &st0);
    if(st0.st_nlink == 0) {
       close(fd);     // lockfile deleted, create a new one
       continue;
    }
    do_something();
    unlink(lockfile); // nlink :=0 before releasing the lock
    flock(fd, LOCK_UN);
    close(fd);        // release the ino if no other proc 
    return true;
}
return false;
于 2018-06-27T20:18:46.083 に答える