flock – ファイル/ディレクトリにロックを掛けてコマンド実行を直列化する

ロック・排他制御
スポンサーリンク

flock はファイル(またはディレクトリ)に共有/排他ロックを取得し、そのロックを保持したままコマンドを実行できるユーティリティです。スクリプトの多重起動防止や、並列処理のクリティカルセクション保護に使われます。ロック対象が存在しない場合は作成されます。(man7.org, EuroLinux)

構文(Syntax)

# 形式1: ロック対象を指定してコマンドを実行
flock [OPTIONS] FILE|DIR COMMAND [ARG...]

# 形式2: シェルの FD をロック(exec 等で FD を開いてから)
flock [OPTIONS] FD

# 便利形: 文字列でコマンドを渡す
flock [OPTIONS] FILE|DIR -c 'SHELL_COMMANDS'
  • 既定は排他ロック。共有ロックは -s。取得できない場合は待機します(-n で即時失敗)。(man7.org)

主なオプション一覧

オプション説明使用例
-s, --shared共有ロック(読取側など複数可)flock -s /tmp/data.lock -c 'cat data' (man7.org)
-x, --exclusive (-e 同義)排他ロック(書込側1つのみ、既定)flock -x /var/lock/job.lock myjob (man7.org)
-n, --nonblock取得できなければ即時失敗flock -n /tmp/backup.lock -c './backup' (man7.org)
-w, --timeout SECタイムアウト秒を指定flock -w 30 /tmp/lock -c 'do_slow' (man7.org)
-E, --conflict-exit-code N競合時の終了コードを N にflock -n -E 100 /tmp/lock cmd (ManKier)
-o, --closeコマンド実行前にロックFDを閉じる(子プロセスへロックを継承させない用途)flock -o /tmp/lock -c 'spawn-children' (ManKier)
-F, --no-forkフォークせずに直接コマンドを実行(--close非両立flock -F /tmp/lock cmd (ManKier)
-c 'CMD'コマンド文字列をシェルに渡すflock /tmp/l -c 'echo hi; sleep 1' (man7.org)
-u, --unlock明示的にアンロック(FDモードで使用)flock -u 200 (man7.org)
-v, --verbose / -h, --help / -V, --version逐次ログ / ヘルプ / バージョンflock -v -n /tmp/lock true (man7.org)

-o は「実行前に FD を閉じる」ため、子プロセスにロックを持たせたくない場合に有用です。--no-fork-F)と同時指定は不可です。(ManKier)

実行例

多重起動を防ぐ(即時失敗)

説明: すでに動作中なら即終了(終了コード 1 など)。
コマンド:

flock -n /var/lock/myjob.lock -c '/usr/local/bin/myjob'
echo "exit=$?"

出力例(ロック獲得失敗時):

exit=1

-E で任意コードに変更可) (man7.org, ManKier)

cron で“かぶり”を防止

説明: 1分おきでも重ならないように。
コマンド(crontab 行):

*/1 * * * * flock -n /tmp/backup.lock -c '/usr/local/sbin/backup'

(ex1-lab)

FD モードでクリティカルセクションを囲む(シェル)

説明: スクリプト全体でロックを保持。
コマンド:

exec 200>/var/lock/task.lock          # FD=200 を開く(存在しなければ作成)
flock -n 200 || { echo "busy"; exit 1; }  # 取れなければ即終了

# ここからクリティカルセクション
update_db
generate_report

flock -u 200   # 明示的にアンロック(終了時にFDが閉じられても解除されます)

(man7.org, Stack Overflow)

共有ロックで“読み手”を並列許可

説明: 読み取り処理は並行、書き込みは別途排他ロックで制御。
コマンド:

flock -s /tmp/data.lock -c 'cat bigdata.csv | wc -l'

(man7.org)

ディレクトリをロック対象にする

説明: ファイルだけでなくディレクトリにもロックできます。
コマンド:

flock -w 10 /var/lock/myapp 'sh -c "touch /tmp/doing; sleep 2"'

(EuroLinux)

エラー例:--no-fork と --close の併用

説明: 併用するとロックを保持するプロセスがなくなるためエラー。
コマンド:

flock -F -o /tmp/lock -c 'echo NG'

出力例(例): オプション不正のエラー
根拠: 両者は非両立です。(ManKier)

関連コマンド

  • flock(2) : カーネルのアドバイザリロックAPI。NFS などでの挙動差の説明もこちらにあり。(man7.org)
  • fcntl(2) : POSIX レコードロック(NFS での相互運用に利用)。(man7.org)
  • lockfile(procmail)/ setlock(daemontools): ロックファイルを用いる別系統の直列化ツール。
  • mkdir の原子作成を使う簡易ロック:手軽だが解除漏れ検知などは自前実装が必要。

備考

  • アドバイザリ: flock のロックは協調的(アドバイザリ)です。ロックを無視して I/O することも可能なので、協調する全プロセスで flock など同一方式を用いてください。(man7.org)
  • NFS / ネットワークFS: Linux 2.6.12 以降の NFS クライアントでは、flock()fcntl のバイト範囲ロックでエミュレートされ、相互に干渉します(排他は書き込み用にオープンが必要)。古い環境・他実装では非対応/局所動作のことがあるため注意。(Arch Linux マニュアルページ)
  • ディスクリプタ継承: fork で複製された子は同じロックを保持できます。子にロックを持たせたくない場合は --close を検討。(ManKier, ウィキペディア)
  • ロック対象の種類: ファイル/ディレクトリどちらでも可。対象が無ければ作成されます。(EuroLinux)
  • 終了コード: 競合で失敗した場合は既定で 1 を返します(-E で変更可)。-n なしでは待機します。(man7.org, ManKier)

参考

スポンサーリンク
Bash玄

はじめまして!Bash玄です。

エンジニアとしてシステム運用に携わる中で、手作業の多さに限界を感じ、Bashスクリプトを活用して業務を効率化したのがきっかけで、この道に入りました。「手作業は負け」「スクリプトはシンプルに」をモットーに、誰でも実践できるBashスクリプトの書き方を発信しています。

このサイトでは、Bashの基礎から実践的なスクリプト作成まで、初心者でもわかりやすく解説しています。少しでも「Bashって便利だな」と思ってもらえたら嬉しいです!

# 好きなこと
- シンプルなコードを書くこと
- コマンドラインを快適にカスタマイズすること
- 自動化で時間を生み出すこと

# このサイトを読んでほしい人
- Bashに興味があるけど、何から始めればいいかわからない人
- 定型業務を自動化したい人
- 効率よくターミナルを使いこなしたい人

Bashの世界に一歩踏み出して、一緒に「Bash道」を極めていきましょう!

Bash玄をフォローする

コメント