C#:静的メソッドが複数のスレッドから呼び出された場合はどうなりますか?


93

私のアプリケーションには、複数のスレッドから同時に呼び出される静的メソッドがあります。データが混同される危険性はありますか?

最初の試みでは、メソッドは静的ではなく、クラスの複数のインスタンスを作成していました。その場合、私のデータはどういうわけか混乱しました。たまにしか発生しないため、これがどのように発生するかはわかりません。まだデバッグ中です。しかし今、メソッドは静的です。今のところ問題はありません。多分それは運だけです。よくわかりません。


回答:


96

メソッド内で宣言された変数(「キャプチャされた」変数を除く)は分離されているため、固有の問題は発生しません。ただし、静的メソッドが共有状態にアクセスする場合、すべてのベットはオフになります。

共有状態の例は次のとおりです。

  • 静的フィールド
  • 共通キャッシュからアクセスされるオブジェクト(非シリアル化)
  • 入力パラメーター(およびそれらのオブジェクトの状態)を介して取得されたデータ(複数のスレッドが同じオブジェクトに接触している可能性がある場合)

状態を共有している場合は、次のいずれかを行う必要があります。

  • 共有できるようになったら状態を変更しないように注意してください(より良い:不変オブジェクトを使用して状態を表し、ローカル変数に状態のスナップショットを作成します。つまりwhatever.SomeData、繰り返し参照するのではなく、ローカル変数にwhatever.SomeData 1回読み込んでから、変数を使用してください-これは不変の状態でのみ役立つことに注意してください!)
  • データへのアクセスを同期します(すべてのスレッドが同期する必要があります)-相互に排他的または(より詳細な)リーダー/ライター

1
@Diego-そのコメントは私または@Holliを対象としていますか?
Marc Gravell

Holliに、返信に実用的な情報を追加するだけです。
ディエゴペレイラ

1
@Marc「メソッド内で宣言された変数(「キャプチャされた」変数の可能性のある例外を含む)が分離されている」に完全に同意することはできません。静的メソッドで宣言されているファイルハンドルについて考えます。その後、他のスレッドがハンドルを使用しているときに、1つのスレッドがハンドルにアクセスできます。予期しない動作が発生します。または、「キャプチャされた」変数は「ファイルハンドル」も意味していましたか。
prabhakaran 2012

9
@prabhakaranファイルハンドルがメソッド変数の場合、そのスコープその呼び出し元のみです。他の呼び出し元は別の変数と話します(メソッド変数は呼び出しごとです)。現在、基になるファイルへのアクセスは別の問題ですが、c#や.NETとは無関係です。ハンドルが共有されていない場合、このシナリオが発生する可能性が高いと、ある種のミューテックス/ロックが予想されます。
Marc Gravell

28

はい、それは運です。;)

メソッドが静的かどうかは関係ありません。重要なのは、データが静的かどうかです。

各スレッドが独自のデータセットを持つ独自のクラスの個別のインスタンスを持つ場合、データが混同されるリスクはありません。データが静的である場合、データのセットは1つだけであり、すべてのスレッドが同じデータを共有するため、データを混同しないようにする方法はありません。

別々のインスタンスのデータがまだ混同されている場合、それはおそらくデータが実際には分離されていないためです。


6
そのラインを愛した- It doesn't matter if the method is static or not, what matters is if the data is static or not。追加するだけで、静的メソッドのスコープ内で宣言されたローカル変数は、特定のシナリオで問題になるデータのその部分を形成しません。
RBT

素晴らしい答え。たくさん助けてくれました。
フラクタル

15

静的メソッドは、複数のスレッドに適しています。

一方、静的データは、異なるスレッドから同じデータにアクセスする試みを制御して、一度に1つのスレッドのみがデータの読み取りまたは書き込みを行うようにする必要があるため、問題を引き起こす可能性があります。


2
ここでのキーワードは同期です:-)
G. Stoynev

2
読み取りは同時に発生しても問題ありませんが、読み取りと書き込みを同時に行うと予期しない動作が発生します
Freestyle076

9

MSDNは常に言う:

この型のすべてのpublic static(Visual BasicではShared)メンバーはスレッドセーフです。インスタンスメンバーは、スレッドセーフであるとは限りません。

編集:ここの連中が言うように、常にそうであるとは限らず、明らかにこれはBCLで​​このように設計されたクラスに適用され、これが適用されないユーザー作成クラスには適用されません。


3
ふew!最後に、MSDNのドキュメントで頻繁に見られるこのメモの意味を理解しました。したがって、基本的に、MSがBCLで静的メソッド(このノートが公開されている場所)を設計するとき、そのメソッドのスコープ外の変数/メンバー/状態にはアクセスしません。それらは、メソッドのロジックを実装するためにのみ、メソッドスコープのローカル変数に完全に依存しています。あなたが共有してくれてとてもうれしいです。
RBT

@マルコテ、反対は本当ではないですか?インスタンスごとに1つあるため、インスタンスメンバーは安全です。ただし、静的メンバーはそのクラスのすべてのインスタンス間で共有されるため、スレッドセーフではありませんか?quora.com/…–
フラクタル

1
場合によります。デフォルトではインスタンスメンバーを安全に扱うことはありません。これがライブラリのセット全体であり、他の多くのものの間でデータの破損を回避する理由です。
Marcote

1
わかりました、@ Marcoteに感謝します。学ぶべきことがたくさんあることを徐々に理解しています。
フラクタル
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.