Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is the C# '??' operator thread safe?

Everyone knows that this is not thread safe:

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

What about this?

public StringBuilder Builder
{
    get { return _builder ?? (_builder = new StringBuilder()); }
}
like image 443
Arsen Mkrtchyan Avatar asked Jun 03 '09 13:06

Arsen Mkrtchyan


1 Answers

BEGIN EDIT

Based on your edited title, the null-coalescing operator itself seems to be thread-safe (see Phil Haack's analysis). It appears, however, that it doesn't guarantee against the potential multiple calls to the StringBuilder constructor.

END EDIT

You have a larger problem with threading, and that is that the Builder property itself represents state that can be shared across threads. Even if you make the lazy initialization thread safe, there's no guarantee that methods consuming Builder are doing it in a thread safe manner.

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

The above will prevent the threading problem in the lazy initialization of _builder, but unless you synchronize your calls to instance methods of StringBuilder, you're not guaranteed thread safety in any methods that consume the Builder property. This is because instance methods in StringBuilder weren't designed to be thread safe. See the below text from the MSDN StringBuilder page.

Any public static (Shared in Visual Basic) members of this type are thread safe. Any instance members are not guaranteed to be thread safe.

If you're consuming StringBuilder in multiple threads, you're probably better served encapsulating it in your class. Make Builder private and expose what behavior you need as a public method:

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

This way you're not writing synchronization code all over the place.

like image 150
Michael Meadows Avatar answered Sep 22 '22 06:09

Michael Meadows