シェルスクリプトの集約ファイル記述子

シェルスクリプトの集約ファイル記述子

私はこれが中断することなくペアリングを提供すると思いましたが、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

私は何が間違っていましたか?

答え1

このアプローチは次のように動作します。

fun()(
  (flock 9 || { echo >&2 "$BASHPID: FAIL: $?"; exit 1; }
   echo "$BASHPID begin"
   sleep 1;
   echo "$BASHPID end"
  ) 9>test
)

これにより、保護する必要があるコマンドが完了しない限り、ロックされたファイルは閉じられません。 (もちろん、testより適切なものと交換する必要があります。例えば使用mktemp。 )

答え2

失敗の理由は次のとおりです。man 2 flock:

Flock()によって生成されたロックは、開かれたファイル記述に関連付けられます(open(2)を参照)。これは、重複したファイル記述子(たとえば、fork(2)またはdup(2)によって生成されたもの)が同じロックを参照し、これらの記述子の1つを使用してロックを変更または解放できることを意味します。

これは、すべてのプロセスが同じファイル記述子を継承するため、プロセスの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

答え3

私が考える鍵は次のとおりです。

  • file descriptor1 予約してstdout使用します。 stdin/out/err以外の9などの他のものを使用する必要があります。人1グループ例が表示されます。

  • flock with file descriptorロックされたファイルは、次のように指定されたファイル記述子番号を使用して開く必要があります。人1グループ例は次のとおりです。

    (
      flock -n 9 || exit 1
      # ... commands executed under lock ...
    ) 9>/var/lock/mylockfile
    

答えは@Stephen Kittのものでした。

関連情報