3

これは、enum値(辞書に保持されている)に関連付けられた文字列を返すメソッドの2つのバリアントです。最初のバリアントは低速ですが、スレッドセーフです。2番目のバリアントは高速ですが、スレッドセーフかどうかはわかりません。初め:

string GetStringForEnum (SomeEnum e)
{
   string str = null;
   lock (someDictionary) //someDictionary is not used anywhere else (only in this method)
   { if (!someDictionary (e, out str)) { someDictionary.Add (e, "somehowCreatedString"); }
   return str;
}

2番目のバリアント:

string GetStringForEnum (SomeEnum e)
{
   string str = null;
   if (!someDictionary (e, out str))
   {
     lock (someDictionary) //someDictionary is not used anywhere else (only in this method)
     { if (!someDictionary (e, out str)) { someDictionary.Add (e, "somehowCreatedString"); }
   }
   return str;
}

2番目のバリアントは毎回「ロック」で使用されるわけではありませんが、スレッドセーフかどうか。

4

3 に答える 3

4

ここには2つの問題があります。

  • lock (someDictionary) -辞書が他の場所で使用されていない場合でも、これはお勧めできません。これは理論的な議論ですが、Dictionaryクラスの(将来の)コードはそれ自体をロックする可能性があります。

  • if (!someDictionary (e, out str)) without a lock. I assume this is a call to TryGetValue(). This simply is not thread-safe, your Read could be interrupted by a Write in another thread. This could end in all sorts of errors (index out of range, null reference). The errors will be very rare (= hard to reproduce).

于 2012-04-04T08:13:30.840 に答える
3

ドキュメントDictionaryは、スレッドセーフに関するセクションがあります。

コレクションが変更されていない限り、 ADictionary(Of TKey, TValue)は複数のリーダーを同時にサポートできます。それでも、コレクションを介して列挙することは、本質的にスレッドセーフな手順ではありません。列挙型が書き込みアクセスと競合するまれなケースでは、列挙型全体でコレクションをロックする必要があります。読み取りと書き込みのために複数のスレッドがコレクションにアクセスできるようにするには、独自の同期を実装する必要があります。

スレッドセーフな代替手段については、を参照してくださいConcurrentDictionary(Of TKey, TValue)

それで:

  • TryGetValue読み取り専用であるため、複数のスレッドから安全に使用できます。ただし、他のコードが同時に辞書を書き込んでいる場合(コードが行っている場合)は安全ではありません。
  • 辞書をロックしない限り、値を追加することは決して安全ではありません。
  • aを使用するのConcurrentDictionaryは簡単な解決策ですが、最初のバージョンよりも速くはないかもしれません(すべての操作でロックされると思います)。

補足:プライベートではないフィールド(ここではフィールドがsomeDictionaryあり、そうであるかどうかはわかりprivateません)をlockターゲットとして使用することはお勧めしません。理論的には、外部コードもlockユーザーの知らないうちに決定する可能性があるためです(実際にはこれは起こらないでしょうが、理論的にも正しくないのはなぜですか?)

于 2012-04-04T08:08:38.033 に答える
2

.NET 4を使用する場合はConcurrentDictionary、スレッドセーフに使用できます。

于 2012-04-04T08:08:03.820 に答える