C# C&x27';操作员线程安全?
每个人都知道这不是线程安全的:C# C&x27';操作员线程安全?,c#,.net,thread-safety,null-coalescing-operator,C#,.net,Thread Safety,Null Coalescing Operator,每个人都知道这不是线程安全的: public StringBuilder Builder { get { if (_builder != null) _builder = new StringBuilder(); return _builder; } } 这个怎么样 public StringBuilder Builder { get { return _builder ?? (_builder = n
public StringBuilder Builder
{
get
{
if (_builder != null)
_builder = new StringBuilder();
return _builder;
}
}
这个怎么样
public StringBuilder Builder
{
get { return _builder ?? (_builder = new StringBuilder()); }
}
两个版本的线程安全性都没有;您仍然可以让两个线程同时执行空检查,从而创建单独的对象而看不到另一个。开始编辑 根据您编辑的标题,空合并操作符本身似乎是线程安全的(请参阅)。但是,它似乎不能保证不会对StringBuilder构造函数进行潜在的多次调用 结束编辑 线程有一个更大的问题,那就是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中的实例方法不是设计为线程安全的。请参阅下面的文本
任何公共静态文件(在Visual Studio中共享)
基本)此类型的成员是线程
安全的。任何实例成员都不是
保证线程安全
如果您在多个线程中使用StringBuilder,那么最好在类中封装它。将生成器设置为私有,并将所需的行为公开为公共方法:
public void AppendString(string toAppend)
{
lock (Builder)
{
Builder.Append(toAppend);
}
}
这样你就不会到处写同步代码了。不,原子也不是。给出的答案是正确的,两者都不是线程安全的。事实上,它们基本上是等价的,
??
操作符只是编译器的魔法,可以使代码更精简。如果您想让它成为线程安全的,您需要使用一些同步机制。我自己没有测试过这种方法,但是如果您希望线程安全而不需要锁定方案的开销,并且您不担心可能创建和丢弃对象实例,您可以尝试以下方法:
using System.Threading;
public StringBuilder Builder
{
get
{
if (_builder != null)
Interlocked.CompareExchange( ref _builder, new StringBuilder(), null );
return _builder;
}
}
仅当_builder==null时,对CompareExchange()的调用才会使用StringBuilder的新实例对_builder中的值执行原子替换。联锁类上的所有方法都不需要被线程开关抢占。我只是认为??这是原子操作吗?线程也不安全吗?我不能说空合并操作符是否是原子的,但我的断言是,您有一个更大的问题,因为StringBuilder本质上不是线程安全的。有关空合并操作符的线程安全性的答案,请参阅编辑过的答案(归功于Phil Haack)。它是线程安全的,因为它不会创建争用条件,但是如果条件完美,您可能会得到两个单独的Builder实例。对,它确实引入了争用条件。如果构造了两个StringBuilder,哪一个被分配给
\u builder
?您对使用Interlocated.CompareExchange(ref\u builder,new StringBuilder(),null)有何看法?顺便说一句,共享StringBuilder的实例可能不是一个好主意。SB本质上不是线程安全的,即使它是线程安全的,也不清楚您是否可以跨未同步的线程使用它做任何有意义的事情;空合并运算符不是原子的。空合并运算符只是第一段代码的语法糖。但这里有更大的问题;谁在乎这片土地是否安全?建造者不是线程安全的!对于今后的问题,如果您提供一个措辞谨慎的定义,确切说明“线程安全”对您意味着什么,将会有所帮助。线程安全不是绝对的;相反,如果调用方实现的使用约定与被调用方预期的使用约定兼容,则代码是线程安全的。如果不知道您期望的契约是什么,就无法确定代码是否遵循它。