FIFOベースのセマフォの説明

FIFOベースのセマフォの説明

私は多くのプロセス(何百ものノードで転送/実行されるタスク)でいくつかの並列化を実行しようとしています。私はこの解決策を見つけました: https://unix.stackexchange.com/a/216475

    # initialize a semaphore with a given number of tokens
    open_sem(){
        mkfifo pipe-$$
        exec 3<>pipe-$$
        rm pipe-$$
        local i=$1
        for((;i>0;i--)); do
            printf %s 000 >&3
        done
    }
    
    # run the given command asynchronously and pop/push tokens
    run_with_lock(){
        local x
        # this read waits until there is something to read
        read -u 3 -n 3 x && ((0==x)) || exit $x
        (
         ( "$@"; )
        # push the return code of the command to the semaphore
        printf '%.3d' $? >&3
        )&
    }
    
    N=4
    open_sem $N
    for thing in {a..g}; do
        run_with_lock task $thing
    done 

ここに説明が必要です。

open_sem()

  1. 何をしますかexec 3<>pipe-$$
  2. 後で削除された理由は何ですか?

run_with_lock()

  1. この部分は&& ((0==x)) || exit $x何を意味しますか?
  2. ( "$@"; )- 私が知っている限り、これは渡されたすべての引数のリストです。しかし、ここでは何をしていますか?

これがプロセスを理解する上で重要な障害ですが、プロセス全体を自由に説明してください:)

PS:私はちょうどその投稿の下にコメントしたいのですが、ちょうどサインアップして、そうする評判はありません。他の人にも便利です。ありがとうございます!ジェイ。

ベストアンサー1

まず、一般的なアイデアについて話しましょう。

fifoから読み取ると、読み取りコマンドはデータがfifoに書き込まれるまで完了しません。 fifo に対するすべての読み取りコマンドは、他のプロセスが同じ fifo に書き込むまでスクリプトを「中断」します。

セマフォとして使用できます。

  1. 読み出しコマンドが完了した後にのみ、任意のコマンドXを実行し、
  2. コマンドが完了すると、別のプロセスがセマフォを使用して読み取りコマンドを完了できるように一度書き込みます。

これで、N個の初期プロセスを開始できるように、fifoに書き込むNコマンドを使用してセマフォを設定できます。

したがって、Nコマンドをfifo(この場合はファイル記述子3にバインド)に書き込んで「セマフォ」を初期化すると、長さNのキューが得られます。

繰り返す:任意のコマンドXを取得し、関数でラップし、f()コマンドXの前の行を読み取り、その後に書き込み、ラップされたコマンドをバックグラウンドジョブとして送信します(f X &)。したがって、4つの書き込みコマンドが設定されている場合、readそのコマンドに従って4番目のバックグラウンドジョブが実行され、5番目のジョブが停止します。したがって、コマンドの後にラッパーに書き込みコマンドを追加すると、readX)書き込みコマンドが実行されます。

open_sem()

  1. execプロセスの入出力をリダイレクトしたり、現在のプロセスを置き換えるために使用できます。この場合、ファイルディスクリプタ3をfifoに(書き込み)およびfifoに(読み取り)リダイレクトします。<入力と>出力のため。コマンド引数を指定するとexec(ここでは実行されません)、bashシェルが破損し、対応するPIDがコマンドに置き換えられます。このステップをスキップすると、ファイル記述子3を読み書きするときにfifoにある読み取りおよび書き込みロックは生成されません。
  2. 削除する必要はなく、単にクリーンアップする方法です。

run_with_lock()

  1. このreadコマンドは、FIFOに書き込まれた内容を変数として読み込みますx。この例では、fifoに書き込まれたコマンドはコマンドXの終了ステータス番号を作成するため、以前のXコマンドが正常に終了したことを確認するために使用できます(コード0)。変数が 0 でない場合はx終了し、終了状態は変数 x に格納されます。
  2. 最初の引数run_with_lock()はコマンドで、残りの引数はそのコマンドの引数であると仮定します。したがって、("$@")&パラメータ付きのコマンドはバックグラウンドで送信されたサブシェルで実行されます。

おすすめ記事