2009-03-24 15 views
7

スレッドの安全性とローカル変数

Increment() 
{ 
    int i = getFromDb(); // get count for a customer from db 
}; 

そして、これがインクリメントますインスタンスクラスである(毎回お客様 - インスタンスオブジェクト - 買い物をする)、これは、可変スレッドセーフ?各スレッドが独自のスタックなどを取得するため、ローカル変数はスレッドセーフであると聞きます。

また、この変数は共有状態であると考えていますか?思考部に欠けているのは、この変数がさまざまな顧客オブジェクト(例えば、John、Paulなど)と連携しているため、スレッドセーフですが、これは欠陥があり、並行プログラミングの経験がないことです。これはとても素朴に聞こえますが、一般的な同期コーディングのような同時コーディングでは多くの経験がありません。

編集:関数呼び出しgetFromDb()は質問の一部ではなく、値が関数から割り当てられたことを示す単なる呼び出しであるため、誰もそのスレッドの安全性を推測するとは思わないDBからのデータ。 :)

EDIT 2:getFromDbのスレッドの安全性は、読み取り操作のみを行うため、保証されています。

答えて

33

iローカル(メソッド)の変数として宣言し、それだけで通常Increment()のスタック・フレーム内に存在します - そうそう、iは、スレッドセーフです...(私はコメントすることはできませんが、 on getFromDb)。場合以外

  • Incrementイテレータブロックである(すなわち、yield return又はyield breakを使用)
  • iが匿名メソッド(delegate { i = i + 1;})またはラムダで使用される(foo => {i=i+foo;}

上記の2つのシナリオでは、スタックの外側に露出される場合がありますが、yああ、どちらもやっている。それらは自明他のスレッドにさらされているようフィールド(クラスの変数)は、ないスレッドセーフであることを

は注意してください。これは、すべてのスレッドが自動的に同じフィールドを共有するため(スレッド静的フィールドを除く)、staticフィールドではさらに顕著になります。

+0

+1(完全なものではないメソッドとイテレータブロックの説明。静的クラスとスレッドセーフは、個人的に把握するのが最も簡単なコンセプトです。) – dotnetdev

+0

IMHO、リストされた例外でも、ローカル変数メソッドの呼び出しごとに固有の_still_です。つまり、スレッドの安全でない方法であっても、メソッドのコンテキスト外でアクセスすることはできますが、同じメソッドへの別の呼び出しのコンテキストでは、_same_ローカル変数に対してスレッドセーフです。 –

5

このステートメントには、関数呼び出しと代入の2つの部分があります。

変数がローカルなので、代入はスレッドセーフです。このメソッドを呼び出すたびに、独自のバージョンのローカル変数が取得されます。ローカル変数は、メモリ内の別の場所にある別のスタックフレームに格納されます。

getFromDb()の呼び出しはスレッドセーフであるかどうかは、実装によって異なります。

2

変数がメソッドに対してローカルであれば、スレッドセーフです。静的変数の場合は、デフォルトではありません。

class Example 
{ 
    static int var1; //not thread-safe 

    public void Method1() 
    { int var2; //thread-safe 
    } 
} 
1

あなたのintはスレッドセーフですが、大文字と小文字の区別はおそらくスレッドセーフではありません。それぞれのスレッドには独自のスタックトレースがあり、各スレッドには独自のiがあるため、あなたのintは、あなたが言ったようにスレッドセーフです。ただし、スレッドはすべて同じデータベースを共有しているため、データベースアクセスはスレッドセーフではありません。データベースアクセスを適切に同期させて、各スレッドが正しい瞬間にのみデータベースを参照するようにする必要があります。

並行性とマルチスレッド化でいつも同じように、情報の読み取りのみを行う場合は、DB上で同期する必要はありません。 2つのスレッドがDBから同じ情報セットを読み書きしようとするとすぐに同期する必要があります。

1

私は「スレッドセーフ」になるでしょう。各スレッドは、あなたが提案したようにスタックの上に自分のコピーを持っています。実際の質問はgetFromDb()スレッドセーフの内容ですか?

1

iはローカル変数なので、共有状態ではありません。

getFromDb()が、たとえばoracle sequenceまたはSQL Serverの自動インクリメントフィールドから読み取っている場合、dbは同期(ほとんどの場合、レプリケーション/分散型DBを除く)を処理しているため、おそらく呼び出したスレッドに結果つまり、DBはすべてのgetFromDB()呼び出しが異なる値を取得することを保証しています。

通常、スレッドセーフティは少しの作業です - 変数の型を変更することは、スレッドがデータにアクセスする方法に依存するため、スレッドの安全性をほとんど損なうことはありません。一連のロック/モニタを調整しようとするのではなく、すべてのコンシューマが同期するキューを使用するようにアルゴリズムを改造することで、頭痛を軽減できます。または可能であればアルゴリズムをロックフリーにする方がよい。

1

私は構文的にスレッドセーフです。しかし、インスタンス変数の値、インスタンスメソッドの戻り値をiに割り当てると、共有データは複数のスレッドによって操作されます。

関連する問題