8

これがスレッドセーフでないことは誰もが知っています。

public StringBuilder Builder
{
    get 
    {
        if (_builder != null)
            _builder = new StringBuilder();
        return _builder; 
    }
}

これはどうですか?

public StringBuilder Builder
{
    get { return _builder ?? (_builder = new StringBuilder()); }
}
4

6 に答える 6

10

これは多かれ少なかれスレッドセーフではありません。2 つのスレッドが同時に null チェックを行うこともできます。したがって、別々のオブジェクトを作成し、もう一方は表示されません。

于 2009-06-03T13:19:19.873 に答える
10

編集開始

編集したタイトルに基づいて、null 合体演算子自体はスレッドセーフのようです ( Phil Haack の分析を参照)。ただし、StringBuilder コンストラクターへの潜在的な複数の呼び出しに対して保証されていないようです。

編集終了

スレッドにはより大きな問題があります。つまり、 Builder プロパティ自体がスレッド間で共有できる状態を表しているということです。遅延初期化をスレッド セーフにしたとしても、Builder を使用するメソッドがスレッド セーフな方法でそれを行っているという保証はありません。

// below code makes the getter thread safe
private object builderConstructionSynch = new object();
public StringBuilder Builder
{
    get
    {
        lock (builderConstructionSynch)
        {
            if (_builder == null) _builder = new StringBuilder();
        }
        return _builder;
    }
}

上記により、_builder の遅延初期化におけるスレッド化の問題が回避されますが、StringBuilder のインスタンス メソッドへの呼び出しを同期しない限り、Builder プロパティを使用するメソッドでスレッド セーフが保証されません。これは、StringBuilder のインスタンス メソッドがスレッド セーフになるように設計されていないためです。MSDN StringBuilder ページの以下のテキストを参照してください。

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

複数のスレッドで StringBuilder を使用している場合は、クラスにカプセル化する方がよいでしょう。Builder をプライベートにし、パブリック メソッドとして必要な動作を公開します。

public void AppendString(string toAppend)
{
    lock (Builder)
    {
        Builder.Append(toAppend);
    }
}

こうすれば、あちこちに同期コードを書く必要がなくなります。

于 2009-06-03T13:19:29.703 に答える
8

両方のバージョンでいいえ

于 2009-06-03T13:18:53.073 に答える
2

私はこのアプローチを自分でテストしていませんが、ロック スキームのオーバーヘッドなしでスレッド セーフが必要であり、オブジェクト インスタンスの作成と破棄の可能性について心配していない場合は、これを試すことができます。

using System.Threading;

public StringBuilder Builder
{
    get 
    {
        if (_builder != null)
            Interlocked.CompareExchange( ref _builder, new StringBuilder(), null );
        return _builder; 
    }
}

CompareExchange() の呼び出しは、_builder == null の場合にのみ、_builder の値を StringBuilder の新しいインスタンスにアトミックに置換します。Interlocked クラスのすべてのメソッドは、スレッド スイッチによってプリエンプトされないことが保証されています。

于 2009-06-03T13:39:24.123 に答える
2

いいえ、どちらもアトミックではありません

于 2009-06-03T13:19:43.447 に答える