0

名前付き System V セマフォを使用して、OSX および Linux 上のすべてのアプリでファイルをロックしています。どの定義から見ても、最も美しい API ではありません。

動作しているように見えますが、全員がセマフォを使い終わった後、セマフォを適切に破棄する方法がわかりません。

一般的なロジックは次のようになります。

作成:

[1] スレッドまたはプロセスは、ftok() によってファイル用に作成された key_t で設定されたセマフォを開こうとします。セットには 2 つのセマフォが含まれています。[2] セマフォ セットが存在しない場合は、666 パーミッションで作成されます。[3] 「ロック」(セマフォの 1 つ) が解放状態 (値 1) に設定されます。[4] 「参照カウント」(同じセット内の別のセマフォ) がインクリメントされます。

ロック/ロック解除:

[5] をロックするには、スレッドは「ロック」セマフォの値を 1 減らします (元に戻す機能を使用)。したがって、値が既にゼロである場合は待機します。[6] のロックを解除するために、スレッドはそれを 1 つ増やし、他の誰かがロックできるようにします。

破壊:

[7] 「参照カウント」セマフォをデクリメントしようとしています (IPC_NOWAIT フラグを使用)。[8] その値が 0 であることを確認し、[9] セマフォ セットが破棄されます。

(1 つのスレッド内でロックを再帰的にするための、スレッド ローカル ストレージに基づくロジックのレイヤーもあります。)

質問は次のとおりです。

  • 手順 [1] と [2] を同期するにはどうすればよいですか? (セマフォ セットが存在しない場合、星を数えている間に他の誰かによって作成されたため、作成も失敗します)
  • ステップ [4] を [8] と同期させて、[9] で早死にさせないようにするにはどうすればよいですか?
  • 他の競合条件はありますか?

PS: POSIX セマフォにはより優れた API がありますが、ここで説明されているように sem_inlink() の動作を乗り切ることはできないと思います。

セマフォを再作成または再接続するための sem_open() の呼び出しは、 sem_unlink() が呼び出された後に新しいセマフォを参照します。

だから私は彼らを解放する方法がありません...

4

2 に答える 2

1

いくつかのアプローチ:

まず、ファイルをロックすることが目的の場合は、セマフォではなく、またはのようなファイルロック呼び出しを使用します。私見、これが最善のアプローチです。flock(2)fcntl(2)+F_SETLK

第二に、セムを永遠に保管してください。おっしゃる通り、提案は際どいものであり、あなたの言い回しは、新しい sem クライアントがいつでも現れる可能性があることを示唆しています。実際に関心のある sem の作成/破棄を制御するには、別の長期的な sem のような別の同期メカニズムが必要です。エキゾチックになり、これを専用の「wait-for-zero」( mysembuf.sem_op := 0) デストロイヤーと組み合わせて、refcount sem を監視し、準備を整えることができIPC_RMIDます。うん。ユーザーが指定した参照カウントを使用せずに、単一の永続的なバイナリ セマフォを使用することをお勧めします。

3 番目に、sems という名前の POSIX を使用します。無視sem_unlink()して、代わりに単にsem_close()完了したら (sem_post()もちろん、ロックを解除した後です!)。これは概念的には前のアプローチに似ています-小さな同期プリミティブが持続します-しかし、あなたが言うように、より単純なAPIです。また、 SysV セマフォの致命的な欠陥に対処する必要もありません。

于 2009-08-07T04:08:37.620 に答える
0

これが私がやったことです(この時点では名誉の問題です。目の前のタスクに必要かどうかに関係なく、正しいコードができるまで離れません:))。

作成

[1] 3 つの sem で設定された既存の sem を開いてみてください。失敗した場合は、[2] で作成してみてください。誰かが作成済みで作成に失敗した場合は、[1]に戻ります。このループは、sem が開いているか作成されているか、処理できないエラーのために最終的に終了します。その場合、ボールを持って家に帰ります。(念のため、N回の反復の制限もあります:))。

3 つの sems の 1 つはペイロード、もう 1 つは参照カウント、3 つ目は参照カウントのロックです。[2] lock を 0 に初期化した後、ロック状態になります。

保持

sem セットが [2] によって作成された場合、3 つの sem はすべて 0 から 1 に semoped [3] されます。ペイロードは解放され、参照カウントは 1 であり、ロックは解放されます (元に戻すことはできません)。[1] で開かれた場合、ロックが取得され [4] (-1)、参照カウントがインクリメントされ (+1)、ロックが解放されます (+1)。現時点でロックがゼロの場合、これはブロックされます。待機中に [6] で sem セットが破棄されたためにこの semop が失敗した場合、保持は失敗し、[1] に戻ります。このループの反復回数も制限されています。

リリース

ロックが取得されます [5] (待機ありで -1)、参照カウントが減ります (待機なしで -1)。これが成功した場合、ref カウントが 0 になった場合、sem セットは破棄されます。それ以外の場合 [6] ロックが解除されます (+1)。sem セットが破棄されたためにロックの取得に失敗した場合 -- 何もしません。

保持と解放の間は、通常どおりペイロードが使用されます。

セットごとに 2 つのセマフォの複雑さとオーバーヘッドの他に、問題が 1 つだけあります (致命的な欠陥がわかりました :))。これにより、すべてのクライアントが停止します。Linux で時限待機を使用して、孤立したセマフォを強制終了することはできますが、OSX は通常のばかげた自己であり、時限操作を持たないため、ちょっと困っています...

*...独自のカーネルか何かを書くために立ち去ります...*

于 2009-08-08T05:27:15.797 に答える