Linux では、openat
syscall を使用してファイルを作成し、その存在をテストできます。C/C++ メモリ モデルの観点から言えば、ファイルを作成してその存在を確認すると、同期関係が作成されます。私が知る必要があるのは、これらの同期がすべて互いに連続的に一貫しているかどうかです。(そうであることを確かに望んでいますが、実際にこれを文書化したものをどこにも見たことがありません。)
たとえば、プロセス p1 と p2、およびパス A と B があるとします。
p1がこれを実行する場合: create(A)、次にcreate(B)
そしてp2はこれを実行します: open(B)を試み、次にopen(A)を試みます
他のプロセスが A または B に干渉しない場合、p2 が B を正常に開くことができても A を見つけられない可能性はありますか?
違いがある場合は、すべての操作が 1 つのファイルシステム内で行われると想定できます。
答え1
基盤となるディスクとマルチコア CPU の最適化により、2 つのプロセス間の操作シーケンスの厳密な順序を決定することが必ずしも可能になるわけではありません。時間に依存する動作が発生する可能性がある場合は、セマフォが使用されます。
答え2
同じディレクトリ内のファイルのみ。
読み取りアクセス。ロック ルール: 呼び出し元はアクセスしているディレクトリをロックします。ロックは共有されます。
オブジェクトの作成。ロックのルール: 上記と同じですが、ロックは排他的に取得されます。
オブジェクトの削除。ロックのルール: 呼び出し元が親をロックし、犠牲者を見つけ、犠牲者をロックしてメソッドを呼び出します。ロックは排他的です。
rename()
あれはないディレクトリ間。ロックのルール: 呼び出し元は親をロックし、ソースとターゲットを検索します。 exchange (RENAME_EXCHANGE
フラグ引数内) の場合、両方をロックします。いずれの場合も、ターゲットがすでに存在する場合は、それをロックします。ソースがディレクトリ以外の場合は、それをロックします。両方をロックする必要がある場合は、inode ポインターの順序でロックします。次に、メソッドを呼び出します。すべてのロックは排他的です。注: ソース (および exchange の場合はターゲット) を共有ロックしても問題ない場合があります。リンク作成。ロックルール:
親をロックする
ソースがディレクトリではないことを確認する
ロックソース
メソッドを呼び出します。すべてのロックは排他的です。
ディレクトリ間の名前変更。全体の中で最もトリッキーです。ロックのルール:
ファイルシステムをロックする
親を「先祖優先」の順序でロックします。
ソースとターゲットを見つけます。
古い親がターゲットと等しいかその子孫である場合は失敗します -
ENOTEMPTY
新しい親がソースと等しいかその子孫である場合は失敗します -
ELOOP
交換の場合は、ソースとターゲットの両方をロックします。
ターゲットが存在する場合は、それをロックします。ソースがディレクトリ以外の場合は、それをロックします。両方をロックする必要がある場合は、inode ポインターの順序でロックします。
メソッドを呼び出します。すべてが
->i_rwsem
排他的に行われます。繰り返しますが、ソース (および Exchange の場合はターゲット) を共有ロックすることで回避できる可能性があります。上記のルールは、メソッドによって読み取り、変更、または削除されるすべてのディレクトリが呼び出し元によってロックされることを保証します。
ロックは線形化可能性を強制するので、操作単一のディレクトリに完全に順序付けられています。ただし、読み取りアクセス (1)、オブジェクトの作成 (2)、およびオブジェクトの削除 (3) は、ディレクトリ ロックよりも広いロックを必要としないため、異なるディレクトリでのディレクトリ操作の順序については保証されません。異なる観察者は、ディレクトリの線形履歴が異なる方法でインターリーブされていると見なす可能性があります。