これで途切れることはないと思いましたbegin-end
ペアですが、そうではありません:
#!/bin/bash
fun()(
flock 1 || { echo >&2 "$BASHPID: FAIL: $?"; exit 1; }
echo "$BASHPID begin"
sleep 1;
echo "$BASHPID end"
)
fun &
fun &
fun &
fun &
fun &
fun &
fun &
fun &
fun &
wait
私は何が間違っているのですか?
失敗の理由は man 2 flock
:
Flock()によって作成されたロックは、開いているファイルの説明に関連付けられています(open(2)を参照)。これは、重複するファイル記述子(たとえば、fork(2)またはdup(2)によって作成される)が同じロックを参照し、このロックはこれらの記述子のいずれかを使用して変更または解放できることを意味します。
これは、すべてのプロセスが同じファイル記述子を継承するため、そのうちの1つがロックを実行すると、すべてのプロセスがそれを共有することを意味します。また、同じファイル記述子を2回ロックすることはできません。
このようなものに対する私の通常の解決策は、スクリプト自体をロックすることです(ただし、スクリプトを同時に複数回実行すると問題が発生します)。
#!/bin/bash
fun()(
exec 3<"$0"
flock 3 || { echo >&2 "$BASHPID: FAIL: $?"; exit 1; }
echo "$BASHPID begin"
sleep 1;
echo "$BASHPID end"
)
fun &
fun &
fun &
fun &
fun &
fun &
fun &
fun &
fun &
wait
このアプローチは機能します:
fun()(
(flock 9 || { echo >&2 "$BASHPID: FAIL: $?"; exit 1; }
echo "$BASHPID begin"
sleep 1;
echo "$BASHPID end"
) 9>test
)
これにより、保護する必要のあるコマンドが終了していない限り、ロックが保持されているファイルが閉じられないことが保証されます。 (明らかに、test
をより適切なものに置き換える必要があります例mktemp
を使用します。)