我在类中有属性定义,我只有计数器,这必须是线程安全的,这不是因为get并且set不在同一个锁中,如何做到这一点?
private int _DoneCounter;
public int DoneCounter
{
get
{
return _DoneCounter;
}
set
{
lock (sync)
{
_DoneCounter = value;
}
}
}
Run Code Online (Sandbox Code Playgroud)
Sea*_*n U 23
如果您希望以DoneCounter = DoneCounter + 1保证不受竞争条件限制的方式实施该属性,则无法在该属性的实现中完成.该操作不是原子操作,实际上有三个不同的步骤:
DoneCounter.DoneCounter.您必须防止在任何这些步骤之间发生上下文切换的可能性.锁定getter或setter内部将无济于事,因为该锁的范围完全存在于其中一个步骤(1或3)中.如果要确保所有三个步骤一起发生而不被中断,那么您的同步必须涵盖所有三个步骤.这意味着它必须在包含所有这三个的上下文中发生.这可能最终会成为不属于任何类包含DoneCounter属性的代码.
使用您的物体的人负责照顾线程安全.通常,没有具有读/写字段或属性的类可以以这种方式"线程安全".但是,如果您可以更改类的接口以便不需要setter,则可以使其更加线程安全.例如,如果你知道DoneCounter只增加和减少,那么你可以重新实现它,如下所示:
private int _doneCounter;
public int DoneCounter { get { return _doneCounter; } }
public int IncrementDoneCounter() { return Interlocked.Increment(ref _doneCounter); }
public int DecrementDoneCounter() { return Interlocked.Decrement(ref _doneCounter); }
Run Code Online (Sandbox Code Playgroud)
使用Interlocked类提供原子操作,即本质上是线程安全的,如以下 LinqPad 示例所示:
void Main()
{
var counters = new Counters();
counters.DoneCounter += 34;
var val = counters.DoneCounter;
val.Dump(); // 34
}
public class Counters
{
int doneCounter = 0;
public int DoneCounter
{
get { return Interlocked.CompareExchange(ref doneCounter, 0, 0); }
set { Interlocked.Exchange(ref doneCounter, value); }
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
12746 次 |
| 最近记录: |