2012-04-01 11 views
5

私はそれが次のコードのように、リストの操作を実行するためのスレッドセーフになりC#のロックスコープ:返されたオブジェクトはまだ「ロックされていますか?

// ... 

private List<double> someList = new List<double>(); 

// ... 

public List<double> SomeList 
{ 
    get { lock (this) { return someList; } } 
} 

// ... 

を含むオブジェクトAを有すると仮定します。いくつかの操作が異なるスレッドによって同時に実行できることが分かっています。ロックが解除され

つまり
A.SomeList.Add(2.0); 

または

A.SomeList.RemoveAt(0); 

、?

+5

されます'this'のようにクラスの外部に公開されているオブジェクトを決してロックしてはいけません。 – svick

+0

十分な公正。私は外に露出していないオブジェクトをロックすると仮定します。 –

+0

なぜでしょうか? – surfen

答えて

5

あなたが質問に表示されているロックはあまり役に立ちません。

リスト操作をスレッドセーフにするには、リストのものをラップする独自の追加/削除/ etcメソッドを実装する必要があります。

public void Add(double item) 
{ 
    lock(_list) 
    { 
     _list.Add(item); 
    } 
} 

また、クラスのコンシューマからリスト自体を非表示にする、つまりフィールドを非公開にすることをお勧めします。

+0

私が恐れていたことはありがとうございました。 –

+2

'List 'で 'SyncRoot'にアクセスすることはできません。これは明示的なインタフェース実装なのでです。そして、私はそれを使用する正当な理由はないと考えています。それは主に下位互換性のためだけです。 – svick

+0

@スウィック:ありがとう。修正されました。 – Gebb

12

スレッドセーフティはありません。

lockは、保護するブロックがプロパティが返される直前に解放されるため、Add ad RemoveAtへの呼び出しはロックによって保護されません。

+0

ありがとう、私は何です。 そのスレッドのような状況を安全にするための共通の方法はありますか? –

+0

@ user1162647 - はい、保護する共有オブジェクトの_operations_をロックします。 – Oded

2

ロックは、ロック内のコードの実行が終了すると解放されます。 また、このロックはオブジェクトの現在のインスタンスにのみ影響します

3

lockステートメントの本文を終了すると、ロックが解除されます。つまり、あなたのコードはではなく、スレッドセーフです。

つまり、2つのスレッドが同時に同じオブジェクト上でreturn someListを実行しないようにすることができます。しかし、あるスレッドがAdd()を同時に実行し、別のスレッドがRemoveAt()を実行する可能性があります。これがスレッドセーフではありません。

1

いいえ、ちょうどそのためです。
すでにスレッドセーフであるアーキテクチャを使用して、オブジェクトのスレッドセーフを行う方法があります。

たとえば、オブジェクトを単一スレッドのCOMオブジェクトにすることができます。 COMオブジェクトはスレッドセーフですが、パフォーマンスはお金を払います(遅延して自分のロックを管理しないという価格)。

Create a COM Object in C#

+0

これは、機関車でフライを殺すようなものです。それは実際にはうまくいくかもしれませんが、それを正しく行うことは難しく、後であなたを噛んでしまうかもしれない副作用を導入することができます。 – svick

0

...他の人がすでに述べたが、ちょうど問題を少し形式化するために...

  • まず、lock (this) {...}は、 'スコープ' を示唆している - 例えばusing(){}のように - 内部の変数に対してのみロックします(この場合はこの)。実際には、実際には、ロック/同期の概念全体が非常に役に立たないように、実際には、まったく役に立たないように、
  • lock (this) { return something; }は、まさにロックを解除する何かを戻しています
  • 私が思うような問題は、それがどのように動作するのか理解していると思います。 'lock()'はオブジェクトの状態で '永続化されていない'ので、などを返すことができます。ここではどのように実装されているかを見てください。How does lock work exactly? - 答えはそれを説明しています。それは「クリティカルセクション」です。つまり、変数自体ではなく、変数を使用する「コード」の特定の部分を保護します。どんな種類の同期でも、ロックを保持するために「同期オブジェクト」が必要です。ロックが不要になれば、処分する必要があります。この記事https://stackoverflow.com/a/251668/417747を見て、エステバンは

「最後に、ロック(これは)実際には、パラメータとして渡されたオブジェクトを変更する一般的な誤解があり、いくつかの方法が可能で、非常によくあること策定しましたそれは、読み取り専用、またはアクセスできない。これはfalseです。単にロックキー」は(これは引用です)

  • として機能するために、パラメータとして渡されたオブジェクトを使用すると、いずれかの(通常)のプライベートコード」をロッククラスメソッド、プロパティの... - 何かへのアクセスを同期するあなたは内部でやっています - プライベートメンバーにアクセスして(通常は)他の誰もあなたの同期コードを使わずにアクセスできます。
  • また、スレッドセーフな方法でアクセスできるように、既に内部で '同期'されているリストのようなスレッドセーフな構造を作成します。しかし、ロックを渡したり、ある場所で変数をロックしたり、コードの他の部分がロックを解除したりするようなことはありません(そうでないと、ほとんど決して使用されません)(その場合はEventWaitHandleのあなたのケースでは、1つが別などにオフ発射「遠い」コード)
  • の間で物事を同期させる、選択はI、「同期構造」で行くことだと思う内部で処理されるリスト、すなわち、
関連する問題