为什么';tc#是否允许锁定空值?
C#不允许锁定空值。我想我可以在锁定它之前检查该值是否为null,但是因为我没有锁定它,另一个线程可能会出现并使该值为null!如何避免这种竞争条件?锁定一个从不为空的值,例如为什么';tc#是否允许锁定空值?,c#,multithreading,locking,C#,Multithreading,Locking,C#不允许锁定空值。我想我可以在锁定它之前检查该值是否为null,但是因为我没有锁定它,另一个线程可能会出现并使该值为null!如何避免这种竞争条件?锁定一个从不为空的值,例如 Object _lockOnMe = new Object(); Object _iMightBeNull; public void DoSomeKungFu() { if (_iMightBeNull == null) { lock (_lockOnMe) { if (_
Object _lockOnMe = new Object();
Object _iMightBeNull;
public void DoSomeKungFu() {
if (_iMightBeNull == null) {
lock (_lockOnMe) {
if (_iMightBeNull == null) {
_iMightBeNull = ... whatever ...;
}
}
}
}
还要小心避免双重检查锁定的有趣竞争条件:这里有两个问题: 首先,不要锁定
null
对象。如何区分两个对象(都是null
)是没有意义的
其次,要在多线程环境中安全地初始化变量,请使用双重检查锁定模式:
if (o == null) {
lock (lockObj) {
if (o == null) {
o = new Object();
}
}
}
这将确保另一个线程尚未初始化该对象,并可用于实现单例模式。您不能锁定空值,因为CLR没有可附加SyncBlock的位置,这允许CLR通过Monitor.Enter/Exit同步对任意对象的访问(这是
lock
内部使用的)
为什么C不允许锁定空值
是迄今为止唯一技术上正确的一个,我接受它。这是因为.NET中的监视器使用附加到所有引用类型的同步块。如果您有一个null
变量,则它不引用任何对象,这意味着监视器无法访问可用的同步块
我怎样才能避免这种比赛状态
传统的方法是锁定一个对象引用,您知道它永远不会为
null
。如果您发现自己处于无法保证的情况下,那么我会将其归类为非传统方法。除非您更详细地描述可以使用的特定场景,否则我在这里不能提及更多内容导致可为空的锁定目标。问题的第一部分已经回答,但我想为问题的第二部分添加一些内容
使用不同的对象执行锁定更简单,特别是在这种情况下。
这也解决了在关键部分维护多个共享对象状态的问题,例如员工列表和员工照片列表
此外,当您必须获得对基本类型(如int或decimal等)的锁定时,此技术也很有用
在我看来,如果你像其他人建议的那样使用这种技术,那么你就不需要执行两次空检查。例如,在接受的答案中,Cris使用了两次if条件,因为锁定的对象与实际修改的对象不同,所以这两次条件实际上没有任何区别,如果你锁定的对象不同,那么执行进行第一次空检查是无用的,也是对cpu的浪费
我建议使用以下代码:
object readonly syncRootEmployee = new object();
List<Employee> employeeList = null;
List<EmployeePhoto> employeePhotoList = null;
public void AddEmployee(Employee employee, List<EmployeePhoto> photos)
{
lock (syncRootEmployee)
{
if (employeeList == null)
{
employeeList = new List<Employee>();
}
if (employeePhotoList == null)
{
employeePhotoList = new List<EmployeePhoto>();
}
employeeList.Add(employee);
foreach(EmployeePhoto ep in photos)
{
employeePhotoList.Add(ep);
}
}
}
Happy threading:)为什么不使用静态初始化且始终不是null的成员呢?据我所知,null本质上什么都不是。你怎么能把什么都锁上?换句话说,string myString=null声明了string类型的变量,但这就是它的全部——它不作为一个对象存在,因为它没有任何价值。最好将readonly添加到lock对象中,以调用所需的不可变性。为什么锁定可以阻止其他人访问?iMightBeNull?-1:您的代码仍然容易受到链接到的竞争条件的影响<代码>\u iMightBeNull需要声明为易失性。或者,最好只使用
Lazy
进行延迟初始化。@Douglas怎么会这样?只要在访问\u iMightBeNull
之前始终锁定\u lockome
,您就不需要volatile。@SourceOverflow:上面的代码在锁定\u iMightBeNull
之前首先检查它是否为空。您需要了解内存模型,才能理解为什么会出现这种情况。要快速确认,请参阅您与Paul答案的链接已断开
object readonly syncRootIteration = new object();
long iterationCount = 0;
long iterationTimeMs = 0;
public void IncrementIterationCount(long timeTook)
{
lock (syncRootIteration)
{
iterationCount++;
iterationTimeMs = timeTook;
}
}
public long GetIterationAvgTimeMs()
{
long result = 0;
//if read without lock the result might not be accurate
lock (syncRootIteration)
{
if (this.iterationCount > 0)
{
result = this.iterationTimeMs / this.iterationCount;
}
}
return result;
}