是C#'??' 操作员线程安全?

Ars*_*yan 8 .net c# thread-safety null-coalescing-operator

每个人都知道这不是线程安全的:

public StringBuilder Builder
{
    get 
    {
        if (_builder != null)
            _builder = new StringBuilder();
        return _builder; 
    }
}
Run Code Online (Sandbox Code Playgroud)

那这个呢?

public StringBuilder Builder
{
    get { return _builder ?? (_builder = new StringBuilder()); }
}
Run Code Online (Sandbox Code Playgroud)

Mar*_*ell 10

这没有或多或少是线程安全的; 你仍然可以让两个线程同时进行空检查,从而创建单独的对象而不会看到另一个.


Mic*_*ows 10

开始编辑

根据您编辑的标题,null-coalescing运算符本身似乎是线程安全的(参见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;
    }
}
Run Code Online (Sandbox Code Playgroud)

上面将防止_builder的延迟初始化中的线程问题,但除非您同步调用StringBuilder的实例方法,否则在使用Builder属性的任何方法中都不能保证线程安全.这是因为StringBuilder中的实例方法并非设计为线程安全的.请参阅MSDN StringBuilder页面中的以下文本.

此类型的任何公共静态(在Visual Basic中为Shared)成员都是线程安全的.任何实例成员都不保证是线程安全的.

如果你在多个线程中使用StringBuilder,那么你可能会更好地将它封装在你的类中.使构建器变为私有并公开您需要的行为作为公共方法:

public void AppendString(string toAppend)
{
    lock (Builder)
    {
        Builder.Append(toAppend);
    }
}
Run Code Online (Sandbox Code Playgroud)

这样你就不会在整个地方编写同步代码.

  • 我不能说null-coalescing运算符是否是原子的,但我的断言是你有一个更大的问题,因为StringBuilder本质上不是线程安全的. (3认同)

van*_*van 8

两个版本都没有