2

私は読んでいて、プロパティでsynclockを使用する必要があるかどうかについて矛盾する答えを得ています。

インスタンス オブジェクトのスレッド間でプロパティを取得/設定する必要があるマルチスレッド アプリケーションがあります。現在、同期クロックを使用せずに実装されており、これまでのところ問題に気づいていません。一般的な静的メソッドで synclock を使用していますが、インスタンス クラスを適切かつスレッド セーフな方法で実装したいと考えています。

どんなフィードバックでも大歓迎です。

4

2 に答える 2

4

経験則として、次の条件のいずれかに該当する場合はロックする必要があります。

  • オブジェクトのいずれかのフィールドが複数のスレッドで変更される場合
  • 変更に複数のフィールドへのアクセスが含まれる場合
  • 変更可能なフィールドが Double、Decimal、または構造化された値のタイプである場合
  • 変更に読み取り-変更-書き込みが含まれる場合 (つまり、フィールドに追加するか、あるフィールドに別のフィールドの値を設定する)

その場合、おそらく、それらのフィールドにアクセスするすべてのメソッドまたはプロパティをロックする必要があります。

編集:クラス内でロックするだけでは十分ではないことに注意してください。必要なのは、論理操作全体で問題が発生しないようにすることです。

@Bevan が指摘しているように、呼び出しコードがオブジェクトに複数回アクセスする必要がある場合、クライアント コードは、別のスレッドが「間に」入らないようにするために、その作業の全期間にわたってオブジェクトに対する独自のロックを取得する必要があります。アクセスし、そのロジックを汚します。

また、一度に複数のロックを解除する必要がある場合は、常に同じ順序で取得するように注意する必要があります。スレッド 1 がインスタンス A をロックしてインスタンス B をロックしようとし、スレッド 2 がインスタンス B をロックしてインスタンス A をロックしようとすると、両方のスレッドがスタックして先に進めなくなります。つまり、デッドロックが発生します。

于 2010-11-25T00:44:12.353 に答える
2

個々のメソッドをロックで囲むだけでは、オブジェクトをスレッドセーフにすることはできません。最終的に行うことは、オブジェクトへのアクセスをシリアル化する (遅くする) ことだけです。

このマイナーな例を考えてみましょう:

var myObject = ...
var myThreadSafeList = ...
if (!myThreadSafeList.Contains(myObject))
{
    myThreadSafeList.Add(myObject);
}

myThreadSafeList ですべてのメソッドがロックされていても、 と の呼び出しの間に別のスレッドがリストの内容を変更できるため、これはスレッドセーフではありませContains()Add()

このリストの場合、追加のメソッドが必要です: AddIfMissing():

var myObject = ...
var myThreadSafeList = ...
myThreadSafeList.AddIfMissing(myObject);

ロジックをオブジェクトに移動することによってのみ、両方の操作をロックで囲み、安全にすることができます。

これ以上の詳細がなければ、さらにコメントするのは難しいですが、次のことをお勧めします。

  • すべてのプロパティを読み取り専用にし、誰でもいつでも読み取れるようにする
  • 一緒に変更される一連のプロパティを取得し、ロック内でアトミックに変更を行うミューテーター メソッドを提供する

説明する:

public class Person {
    public string FullName { get; private set; }
    public string FamilyName { get; private set; }
    public string KnownAs { get; private set; }

    public void SetNames( string full, string family, string known) {
        lock (padLock) {
            ...
        }
    }
}
于 2010-11-25T00:53:06.617 に答える