Domanda

Tutti sanno che questo non è thread-safe:

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

Che dire di questo?

public StringBuilder Builder
{
    get { return _builder ?? (_builder = new StringBuilder()); }
}
È stato utile?

Soluzione

BEGIN EDIT

In base al titolo modificato, l'operatore null coalescenza stessa sembra essere thread-safe (vedi di Phil Haack analisi ). Sembra, tuttavia, che non garantisce contro i potenziali più chiamate al costruttore StringBuilder.

FINE EDIT

Hai un problema più grande con filettatura, e cioè che la proprietà del costruttore stesso rappresenta stato che può essere condiviso tra i thread. Anche se si effettua il thread di inizializzazione pigra al sicuro, non c'è alcuna garanzia che i metodi che consumano Builder lo fanno in un modo thread-safe.

// 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;
    }
}

È possibile che questo impedirà il problema filettatura nella inizializzazione differita di _builder, ma a meno che non si sincronizzano le chiamate ai metodi di StringBuilder esempio, non la garanzia di sicurezza filo in qualsiasi metodo che consumano la proprietà Builder. Questo perché i metodi di istanza in StringBuilder non sono stati progettati per essere thread safe. Vedere il testo qui sotto dal pagina MSDN StringBuilder .

  

statici pubblici (in Visual   Basic) di questo tipo sono thread   sicuro. I membri di istanza non sono   garanzia di essere thread-safe.

Se si sta consumando StringBuilder in più thread, probabilmente stai meglio servita incapsulare nella tua classe. Assicurarsi Builder privato ed esporre ciò che il comportamento è necessario come un metodo pubblico:

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

In questo modo non sta scrivendo codice di sincronizzazione in tutto il luogo.

Altri suggerimenti

Questo è né più né meno thread-safe; si potrebbe ancora avere due thread fare il check nulla, allo stesso tempo, in tal modo a creare oggetti separati e non vedere l'altro.

NO per entrambe le versioni

No, non sono atomiche

Le risposte sono corrette, entrambi non sono threadsafe. In realtà, essi sono per lo più equivalenti, e l'operatore ?? è solo la magia del compilatore per rendere il codice più snella. È necessario utilizzare un meccanismo di sincronizzazione, se si desidera che questo diventi threadsafe.

Non ho provato io stesso approccio, ma se si vuole la sicurezza dei thread senza il sovraccarico di un sistema di bloccaggio e non siete preoccupati per creando potenzialmente e scartando un oggetto esempio, si potrebbe provare questo:

using System.Threading;

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

La chiamata a CompareExchange () eseguirà una sostituzione atomica del valore in _builder con una nuova istanza di StringBuilder solo se _builder == null. Tutti i metodi sulla classe Interlocked sono Gauranteed per non essere preempted da interruttori filetto.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top