ファイルをロックした後、使っていたファイル記述子を閉じても、ほかの処理がまだロックを取れないことがあります。逆に、複製した側から解除すると、元の記述子で確保していたはずのロックも外れます。Linuxのflockでは、ロックが番号そのものではなく、その番号が参照する「開いた状態」に結び付くためです。
簡単にまとめると?
- Linuxのflockのロックは、open file descriptionに結び付きます。dupやforkで複製された記述子は、同じロックを参照します。
- 複製の一つを閉じても、同じ開いた状態を参照する記述子が残ればロックは残ります。明示的なLOCK_UNなら、複製側からでも同じロックを解除できます。
- 同じファイルを別にopenすると、独立した開いた状態になります。同じプロセス内でも、片方のロックがもう片方の取得を妨げることがあります。通常の助言的ロックとネットワークファイルシステムの条件は分けて考えます。
ファイル名、記述子、開いた状態を分ける
ファイル記述子は、プロセスが開いたファイルを参照するために使う整数です。一方open file descriptionは、開いたファイルに関するカーネル側の状態を表します。dupで記述子を複製すると、異なる整数から同じopen file descriptionを参照します。forkで引き継がれた記述子も、この共有関係を持ちます。
flock(fd, op)は、fdが指す開いたファイルへロックを設定したり解除したりする呼び出しです。Linux man-pagesのflock(2)は、このロックがopen file descriptionへ関連付けられると説明しています。[1、DESCRIPTION] 「プロセスごとに一個」「ファイル記述子の数字ごとに一個」と考えるだけでは、寿命や解除の挙動を説明しきれません。
ここでは、通常のローカルファイルに対するLinuxのflockの意味を扱います。別のOSでの互換実装や、NFS、SMBでの処理をすべて同じものとはみなしません。また、ファイルの読み取り位置を共有することと、ロックの取得・解除を共有することは、同じ参照関係から生じる別の効果です。
共有ロックと排他ロックは、参加する処理の約束
LOCK_SHは共有ロックです。複数の処理が同じファイルについて共有ロックを持てます。LOCK_EXは排他ロックで、ほかの共有・排他ロックと両立しません。LOCK_UNで既存のロックを外します。[1、DESCRIPTION]
両立しないロックがある場合、通常のflock呼び出しは取得できるまで待つことがあります。待ちたくないならLOCK_NBを合わせて指定します。その状態で競合すれば、−1とEWOULDBLOCKで、今は取得できなかったことが分かります。[1、ERRORS] これは対象ファイルが存在しないことや、記述子が無効であることとは別の失敗です。
通常の助言的ロックでは、flockを無視する処理まで読み書きできなくなるわけではありません。適切なファイル権限があれば、参加しない処理はI/Oを行えます。[1、NOTES] 複数の更新処理を調停したいなら、それぞれが同じロック方式に参加し、取得に成功してから必要な範囲の処理を行う必要があります。
dupした記述子が一つ残る場合
説明用に、一つのファイルを開いた状態をA、その記述子をfd3と呼びます。fd3からLOCK_EXを取得した後、dupでfd4を作ると、fd3とfd4はどちらもAを参照します。この時点で排他ロックが二個に増えるわけではありません。
ここでfd3だけをcloseしても、fd4がAを参照し続けるため、ロックは残ります。別に開いた状態Bから非待機の排他ロックを要求すれば、競合するというのがこの例です。さらにfd4も閉じ、Aを参照する記述子がなくなると、Aに結び付いたロックが解除されます。[1、DESCRIPTION]

ただし、最後の記述子を閉じるまで待つ方法だけが解除の手段ではありません。fd4からLOCK_UNを実行すれば、fd3がまだ残っていてもAのロックを明示的に外せます。「複製した側のロックだけを外したつもり」という解釈では、元の側が守られていると誤認してしまいます。
fork後の親子でも、引き継いだ記述子は同じロックを参照できます。親が自分の記述子を閉じたことだけを根拠に、子に残った参照もなくなったと考えないことが大切です。どの処理が記述子を保持し、どこから明示解除するかまで確認する必要があります。
同じプロセスでも、開き直した側は別の取得になる
同じファイル名をもう一度openし、別の記述子fd5を得た場合は、dupとは違います。新しいopen file description Bは、flockにとって独立です。Aで排他ロックを持っていれば、同じプロセスからBを使って排他ロックを取ろうとしても、拒まれることがあります。[1、DESCRIPTION]
そのため、部品ごとにファイルを開き直し、同じプロセス内だから再取得できるはずだと考える設計は危険です。非待機なら競合を検出できますが、待機する取得では自分の保持したロックを待つ形になり得ます。Linuxのflockはデッドロックを検出しないと記載されています。[1、VERSIONS] 取得順序と所有する参照を設計側で整理します。
本稿の独自モデルでは、Aの取得、dupによる参照追加、片側close、別のBの取得失敗、Aの最後の参照を閉じた後のBの取得成功を順に照合しました。別の系列では、参照が二つ残る状態でLOCK_UNに相当する解除を行い、Bが取得できることも確認しました。これは仕様上の関係を表にした計算であり、実際のカーネルによる待ち時間や競合を測った結果ではありません。
ロックの切り替えと、環境の違いも確認する
共有ロックを排他ロックへ切り替えるときにも、常に保護が途切れないとは限りません。flock(2)は切り替えの原子性を保証せず、元のロックを外してから新しいものを設定する間に、ほかの要求が通る場合があると説明しています。[1、NOTES] 更新のためにロックを強める設計では、その間に状態が変わっていないかを確認する必要があります。
また、通常のLinuxのローカル処理ではflockとfcntlのロックは相互に作用しないと記載されていますが、この説明をNFSやSMBへそのまま広げることはできません。同じマニュアルは、NFSで全ファイル範囲のfcntlロックとして扱う実装や、Linux 5.5以降のSMBで強制的なロックの意味が生じる場合を区別しています。サーバー、プロトコル、マウントの条件でも変わります。[1、VERSIONS、HISTORY]
運用で調べる際は、まず対象がローカルかネットワーク上かを確かめます。そのうえで、同じopen file descriptionを共有しているのか、別に開いた状態同士なのか、すべての更新者が同じロック方式を使うのかを追います。取得に成功したこと、書き込みが終わったこと、データが永続化されたことも別々です。ロックは処理の順番を調停する道具であり、それだけを後二者の証拠にすることはできません。
出典
- Linux man-pages, flock(2)、man-pages 6.19、ページ日付2026-02-08、HTML作成2026-09-09。DESCRIPTION、ERRORS、VERSIONS、HISTORY、NOTESを参照。2026年10月23日確認。図と状態遷移モデルは独自作成。
