2009-08-07 20 views
0

名前付きのSystem Vセマフォを使用して、OSXおよびLinux上のすべてのアプリケーション間でファイルをロックしています。どの定義でもAPIの中で最もきれいです。名前付きSystem Vセマフォを正しく破棄する

これはうまくいくようですが、誰もがそれを実行した後、セマフォを正しく破棄する方法がわかりません。

一般的なロジックは、このようなものです:

作成:

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

ロック/アンロック:

[5]は、スレッド1によって「ロック」セマフォの値をデクリメントロックする(元に戻すと)、それは既にゼロである場合、従って待っ。 [6]をロック解除するには、スレッドは1をインクリメントして、他の誰かがそれをロックできるようにします。

破棄:

[7] "参照カウント" セマフォは(IPC_NOWAITフラグ付き)デクリメントすることを試みています。 [8]その値は0にチェックされ、[9]であればセマフォセットは破棄されます。

(1つのスレッド内でロック再帰を作るために、スレッドローカルストレージに基づいた論理の層もあります。)

質問は次のとおりです。

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

PS:POSIXセマフォは、非常に良くAPIがありますが、私はここで説明したように、私はsem_inlink()の挙動を生き残ることができるとは思わない:(sem_openする

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

だから私は...

答えて

1

いくつかのアプローチそれらを解放する方法がありませんでしょう:あなたの目標は、ファイルをロックする場合

まず、その後、は、ファイルロックコールを使用しますは、flock(2)またはfcntl(2)+F_SETLKのようにセマフォではありません。 IMHO、これは最善のアプローチです。

次に、は、永遠に周りを保つです。あなたが正しいです、提案は賢明です、そしてあなたの言いたいことは、新しいsemクライアントがいつでも出現するかもしれないことを示唆しています。あなたは実際に気にしているsemの作成/破壊を制御するために、独立した、長期的なsemのような別個の同期メカニズムが必要です。あなたはエキゾチックになり、これを専用の "ゼロ待ち受け"(mysembuf.sem_op := 0)駆逐艦と組み合わせて、refcountのsemを見てIPC_RMIDの準備ができました。ヤックユーザーが提供する参照カウントを使用せずに、永続的なバイナリセマフォーを1つだけ持つ方がよいでしょう。

第3、は、POSIXという名前のsemsを使用します。。無視するとsem_unlink()となり、完了したときには単にsem_close()となります(もちろん、ロックを解除するにはsem_post()を実行してください)。これは概念的には以前のアプローチと同じですが、小さな同期プリミティブはそのままですが、より簡単なAPIです。また、SysV semaphores' fatal flawを扱う必要はありません。

+0

私は致命的な欠陥については分かりません。セマフォの作成はアトミックです(私は願っていますか?)。次のプロセスは実際にそれを取得するか、最悪の場合は作成する呼び出しに失敗します(ループ内で再度取得する必要があります)。それから、プロセスの作成が完了するまで(1に設定)、他の人はすでに既存のsemを取得し、 "ロック"(-1で)しようとすると待機します。プロセスを作成するとコントロールが失われますが、それはすべてOKです。 – Eugene

+0

(実際には、私の質問に答えるだけで、ループは欲しかったのです:)) – Eugene

+0

semを永遠に保つのは、Linuxの最大値は通常128セットのような非常に小さいです。少数のファイルだけをロックする必要がありますが、私の単体テストはかなり早く到達します。これが、私が使用しないときに殺す主な理由です。 – Eugene

0

これは私がやったことです(現時点では名誉の問題ですが、手元にあるタスクに必要かどうかにかかわらず正しいコードがあるまでは、私は離れません)。

を作成

は、[2]を作成しようとし失敗した場合、[1] semが、3セムスで設定した既存のオープンにしてください。誰かが既に作成したために作成に失敗した場合は、[1]に戻ります。このループは、オープンまたは作成されたsemで、または私が処理できないエラーのために、最終的に終了します。その場合、私はボールを持って帰宅します。 (私はN inerationsの制限もあります)。

3つのsemsの1つがペイロードであり、もう1つは参照カウントであり、3つ目はrefカウントのロックです。 [2]ロックが0に初期化された後、ロックされた状態。ロックが解除され、SEMセットは[2]、すべての3つのSEMをsemopedれることによって作成された場合

を保持

[3]は0から1にペイロードが放出され、REFカウントが1であり、(元に戻します) 。 [1]で開かれた場合、ロックは取得されます。[4](-1)、refカウントがインクリメント(+1)され、ロックが解除されます(+1)。ロックが現在ゼロであれば、これはブロックされます。このsemopが、我々が待っている間に[6]でセミセットが破棄されたために失敗した場合、保持は失敗し、我々はすべて[1]に戻ります。このループは反復回数も制限されています。

ロックを解除

は、[5](-1待機して)、参照カウントがデクリメントされ(-1ウェイトなしで)を取得します。これが成功した場合、refカウントがゼロになると、semセットは破棄されます。それ以外の場合は[6]ロックが解除されます(+1)。セミセットが破棄されたためロックを取得できない場合は何もしません。

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

セットあたり2セマフォの複雑さとオーバーヘッドのほかに、問題は1つだけです(今は致命的な欠陥があります:)) - クリエイターが[2]と[3]の間でクラッシュしたとき。これにより、すべてのクライアントが死んでしまいます。私はLinux上でタイムドウェイトを使い、孤立したセマフォを殺すことができますが、OSXは普通の愚かな自己であり、時間を計られていないので、ちょっとねじれています...

*か何か...*

関連する問題