如何轻松使这个计数器属性线程安全? [英] How to easy make this counter property thread safe?
问题描述
我在只有计数器的类中有属性定义,这必须是线程安全的,这不是因为 get
和 set
不在同一个锁中,如何做到这一点?
I have property definition in class where i have only Counters, this must be thread-safe and this isn't because get
and set
is not in same lock, How to do that?
private int _DoneCounter;
public int DoneCounter
{
get
{
return _DoneCounter;
}
set
{
lock (sync)
{
_DoneCounter = value;
}
}
}
推荐答案
如果您希望以DoneCounter = DoneCounter + 1
保证不受约束的方式实现该属性竞争条件,它不能在属性的实现中完成.该操作不是原子操作,它实际上分为三个不同的步骤:
If you're looking to implement the property in such a way that DoneCounter = DoneCounter + 1
is guaranteed not to be subject to race conditions, it can't be done in the property's implementation. That operation is not atomic, it actually three distinct steps:
- 检索
DoneCounter
的值. - 加1
- 将结果存储在
DoneCounter
中.
- Retrieve the value of
DoneCounter
. - Add 1
- Store the result in
DoneCounter
.
您必须防止在任何这些步骤之间发生上下文切换的可能性.锁定在 getter 或 setter 内无济于事,因为该锁定的范围完全存在于其中一个步骤(1 或 3)中.如果您想确保所有三个步骤一起发生而不会被中断,那么您的同步必须涵盖所有三个步骤.这意味着它必须发生在包含所有三个的上下文中.这可能最终成为不属于任何包含 DoneCounter
属性的类的代码.
You have to guard against the possibility that a context switch could happen in between any of those steps. Locking inside the getter or setter won't help, because that lock's scope exists entirely within one of the steps (either 1 or 3). If you want to make sure all three steps happen together without being interrupted, then your synchronization has to cover all three steps. Which means it has to happen in a context that contains all three of them. That's probably going to end up being code that does not belong to whatever class contains the DoneCounter
property.
使用你的对象的人有责任照顾线程安全.通常,没有具有读/写字段或属性的类可以通过这种方式成为线程安全的".但是,如果您可以更改类的接口以便不需要 setter,则可以使其更加线程安全.例如,如果您知道 DoneCounter 只会递增和递减,那么您可以像这样重新实现它:
It is the responsibility of the person using your object to take care of thread safety. In general, no class that has read/write fields or properties can be made "thread-safe" in this manner. However, if you can change the class's interface so that setters aren't necessary, then it is possible to make it more thread-safe. For example, if you know that DoneCounter only increments and decrements, then you could re-implement it like so:
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); }
这篇关于如何轻松使这个计数器属性线程安全?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!