2011-01-25 2 views
3

私は多くのマルチスレッドコードを解析しています。私は非常に多くのロックを見ています。いくつかのメソッドは、次のような行に2つのロックを持ちます:同期コードの匂い?

ClassA::foo() 
{ 
    lockA.lock(); 
    lockB.lock(); 

    ...//do some stuff 

    lockB.unlock(); 
    lockA.unlock(); 
} 

私の質問は非常に一般的です(実際のコードは提供できません)。これはコードのにおいですか?これは一般的に悪い習慣ですか?コードを単純化できることは証明できませんが、コードが正しくコーディングされていれば、2つのものをロックする必要はないでしょう。ロックは、同期が必要な一連のリソースを管理する必要があります。リソースの管理と重複する2つのロックがある場合、いくつかのデッドロックの問題がありますか?

洞察があれば教えてください。

おかげで、 JBU

答えて

2

それはそれ自体でコードのにおいを表すものではありませんので、コードの一部は、2つのロックを取る必要がすることは非常に一般的です。これらのロックがの場合は常にとなりますが、それは問題になります。しかし、別々にロックを取る場所が他にある場合は、このパターンは問題ありません。

コードスニペットで唯一コメントしたいのは、RAIIロッククラスを使用してコードを例外セーフにし、他の種類のコードエラーを回避することです(誤っていくつかのコードパスでロック)。

+0

のケースを取得することはありません。 lockA。ロック(); doStuff; lockA.unlock(); lockB.unlock();}(ロック順の逆転に気づく)、デッドロックの条件はありますか?おそらくあなたの答えに追加するには、一貫した順序でロックを行う必要がありますか? – jbu

+0

はい、ロックを一貫した順序で実行する必要があります。 –

3

コンテキストやプロジェクトの範囲によっては、匂いかもしれませんが、そうでないかもしれません。キューに登録されているリストを同期させるために5つのロックを操作すると、何か間違ったことが起こっている可能性があります。一般的に私は共有資源とロックの間に良い1-1の比を持っていたい。

細かいレベルでロックすることが魅力的な場合もあります(リスト全体をロックするのではなく、リストの各アイテムをロックする)。プロファイラーがあなたにロックが大量に提供されていると言うまで、その要望を再現してください。

他の場合、単一のリソースを保護するのではなく、多くの競合が発生しないことを知っている特定のbussiness-logicを保護するために、ロックを使用して複数のロックを1つにまとめることができます。あなたは少しパフォーマンスが落ちるかもしれませんが、10個のロックを取り除くことができれば、それはテーブルにもたらすシンプルさのために通常は価値があります。

あなたの質問に対する答えは質問の形であると思います。なぜあなたのクラスAは2つの共有リソースを同時に使用していますか?一般的には、何らかの種類の単一責任主義の原則を使用して設計段階で回避しようとするものです。通常、共有リソースは誰かに属し、誰かがリソースのロック/ロック解除に関する単一の権限です。確認するために

lockA.lock(); 
//some code 
lockA.unlock(); 
lockB.lock(); 
//some other code 
lockB.unlock(); 

一つの明確なもの:

あなたがメソッドをリファクタリングすることができます任意の方法はあります(つまりLOCKA> lockB)のロックを注文する所定の有限/定義された方法のみロックがあるはずですそれらを昇順に並べ替えます。

別のスレッドのメソッドは、ClassBの::バー(){lockB.lock()のような何かをした場合あなたは

lockA.lock(); 
lockB.lock(); 

や他のいくつかのコードで

lockB.lock(); 
lockA.lock(); 
+0

良い説明とロック設計のアプローチの説明のため+1。 – Rachel

+0

マルチスレッドアプリケーションを扱う際の最善の設計原則は、「単一責任原則」を提案しています。また、マルチスレッドアプリケーションを扱う際に異なる最良の設計アプローチを説明するリファレンスもあります。 – Rachel

関連する問題