1

私はC#のマルチスレッドの専門家ではありません。テストでトリガーするのが難しい、デバッグがほぼ不可能な競合状態を確実に防止したいと思います。要件(私のアプリケーションは、IISまたはASP.NETを使用せずに、マルチスレッドのHTTPサーバーで使用されるユーティリティクラスです)は、クラスの各インスタンスがそのインスタンスの一意の識別子を持っていることです。

HTML表現のようにシリアル化された長さがあるため、問題を回避するために重量のあるGUIDを使用したくありません。

私の質問はこれです:クラスのUniqueWidgetをこの要件に適したパターンの下に設定するための単純なパターンですか?実装に負担がかからないことを願って、より良い、より安全なパターンはありますか?

public abstract class Widget : Node
{
    private static int UniqueCount = 0;
    private static object _lock = new object();
    protected int Unique { private set; get; }

    protected Widget() : base()
    {
        // There could be a subtle race condition if this is not thread-safe
        // if it is used with a multi-threaded web server
        lock (_lock)
        {
            UniqueCount += 1;
            Unique = UniqueCount;
        }
    }  

}
4

2 に答える 2

2

この答えから:

競合状態の影響を受けないことが保証されている方法でプロパティを実装しようとしている場合DoneCounter = DoneCounter + 1、プロパティの実装では実行できません。その操作はアトミックではなく、実際には3つの異なるステップです。

  1. の値を取得しますDoneCounter
  2. 1を追加
  3. 結果をに保存しDoneCounterます。

これらのステップのいずれかの間でコンテキストスイッチが発生する可能性を防ぐ必要があります。ゲッターまたはセッターの内部をロックしても、そのロックスコープは完全にいずれかのステップ(1または2)内に存在するため、役に立ちません。3つのステップすべてが中断されることなく同時に実行されるようにする場合は、同期で3つのステップすべてをカバーする必要があります。つまり、3つすべてを含むコンテキストで発生する必要があります。DoneCounterそれはおそらく、プロパティを含むクラスに属さないコードになるでしょう。

スレッドセーフの面倒を見るのは、オブジェクトを使用する人の責任です。一般に、読み取り/書き込みフィールドまたはプロパティを持つクラスは、この方法で「スレッドセーフ」にすることはできません。ただし、セッターが不要になるようにクラスのインターフェースを変更できる場合は、よりスレッドセーフにすることができます。たとえば、DoneCounterがインクリメントとデクリメントのみを行うことがわかっている場合は、次のように再実装できます。

private int _doneCounter;
public int DoneCounter { get { return _doneCounter; } }
public void IncrementDoneCounter() { Interlocked.Increment(ref _doneCounter); }
public void DecrementDoneCounter() { Interlocked.Decrement(ref _doneCounter); }
于 2013-02-01T20:31:04.933 に答える
1

前述のように、+=(および関連する)操作はスレッドセーフではありません。単純な数値の増分を行う場合はInterlocked.Increment、;を使用するだけです。古い値を返し、完全にスレッドセーフです。

public abstract class Widget : Node
{
    private static int UniqueCount = 0;
    protected int Unique { private set; get; }

    protected Widget() : base()
    {
        Unique = Interlocked.Increment(ref UniqueCount);
    }  
}
于 2013-02-01T20:37:52.877 に答える