【发布时间】:2013-10-23 14:09:36
【问题描述】:
[编辑:看起来原始问题涉及双精度而不是整数。所以我认为如果我们将整数更改为双精度,这个问题就成立了。]
我很少遇到从多个线程中使用的类中读取整数属性的问题,该类有时会返回零值。初始化后值不会更改。
这个question 解决了这个问题。共识是,即使我正在访问一个整数,我也需要同步属性。 (一些原始答案已被删除)。我没有在那里选择答案,因为我还没有解决我的问题。
所以我对此进行了一些研究,但我不确定要使用 .Net 4 的哪种锁定机制,或者这些锁定是否应该在类本身之外。
这是我想使用的:
public class ConfigInfo
{
private readonly object TimerIntervalLocker = new object();
private int _TimerInterval;
public int TimerInterval
{
get
{
lock (TimerIntervalLocker) {
return _TimerInterval;
}
}
}
private int _Factor1;
public int Factor1
{
set
{
lock (TimerIntervalLocker) {
_Factor1 = value;
_TimerInterval = _Factor1 * _Factor2;
}
}
get
{
lock (TimerIntervalLocker) {
return _Factor1;
}
}
}
private int _Factor2;
public int Factor2
{
set
{
lock (TimerIntervalLocker) {
_Factor2 = value;
_TimerInterval = _Factor1 * _Factor2;
}
}
get
{
lock (TimerIntervalLocker) {
return _Factor2;
}
}
}
}
但我听说这非常慢。
另一种选择是在用户端锁定ConfigData 的实例,但这似乎需要做很多工作。我见过的另一种选择是Monitor.Enter 和Monitor.Exit,但我认为 Lock 是相同的东西,语法更少。
那么制作类的属性线程的最佳实践是什么 安全吗?
【问题讨论】:
-
如果您在初始化后不改变状态(初始化被定义为在其他线程使用该类之前),那么您的代码已经完全是线程安全的,没有任何锁。
-
最好开发这样的设计来避免这种情况。我会先研究整个事情的设计。
-
@RichShealer 如果
TimerInterval永远为零,则只有两种可能性:(1)您在两个因素都设置为非零值之前访问它,或者(2)正在设置一个或两个因素为零。没有其他可能性(除了极不可能的因素,即因子设置为当相乘时会溢出导致为零的值) -
@RichShealer 这对公共设置器来说不是一个好例子——听起来你需要在构造函数中设置只读字段。
-
“我听说这太慢了”——不要通过阅读别人的代码来进行性能分析。通过运行代码进行性能分析!一个非竞争锁大约需要 10-100 纳秒。争用锁是任意缓慢的。正确的解决方案几乎总是重构您的程序以避免争用,并采取 10-100 ns 的命中率。
标签: c# multithreading c#-4.0 properties thread-safety