我在应用程序中得到“对volatile字段的引用不会被视为volatile”警告。我理解为什么。
作为一个简单的例子,下面的代码会使问题线程安全,即使我仍然会收到警告吗?
private volatile int myVal = 10;
private int myNonVolatileNumber = 50;
private static readonly object lockObject = new object();
private void ChangeValue(ref int Value)
{
lock (lockObject)
{
Value = 0;
}
}
private void MyMethod()
{
ChangeValue(ref myVal); //Warning here
ChangeValue(ref myNonVolatileNumber); //no warning
}
答案 0 :(得分:2)
锁定会强制双方都有内存障碍,所以是的,您的示例是线程安全的。
答案 1 :(得分:1)
你几乎自己回答:
ChangeValue(ref myVal); //Warning here
ChangeValue(ref myNonVolatileNumber); //no warning
编译的ChangeValue()只有一个副本,里面的代码应该实现'volatile'行为。但是编译器(Jitter)在编译时无法预测所有调用。唯一的选择是将每个 ref参数视为volatile,这将是非常低效的。
但是看看@ Steven的评论,volatile
和无用一样好,应该避免。
答案 2 :(得分:1)
可能不需要在您使用过的地方使用volatile关键字。
这个SO问题回答了所有应该使用volatile关键字的地方:
答案 3 :(得分:0)
会出现什么问题
private int val = 10;
private var valLock = new object();
private int nonVolatileNumber = 50;
private var nonVolatileNumberLock = new object();
public int Value
{
get { lock(valLock) return val; }
set { lock(valLock) val = value; }
}
public int NonVolatileNumber
{
get { lock(nonVolatileNumberLock) return nonVolatileNumber; }
set { lock(nonVolatileNumberLock) nonVolatileNumber = value; }
}
,这里唯一的风险是后续代码访问该属性的私有成员。
对于64位系统上的32位整数,甚至64位整数,因为读取将是原子的,你可以像这样使用Interlocked类......
private int val = 10;
public int Value
{
get { return val; }
set { Interlocked.Exchange(ref val, value); }
}
如果是更复杂的类型,您可以使用ReadWriterLockSlim ...
private SomeStructure complex;
private var complexLock = new ReadWriterLockSlim();
public SomeStructure Complex
{
get
{
complexLock.EnterReadLock();
try
{
return complex;
}
finally
{
complexLock.ExitReadlock();
}
}
set
{
complexLock.EnterWriteLock();
try
{
return complex;
}
finally
{
complexLock.ExitWritelock();
}
}
}
这比标准锁更好,因为它允许多个同时读取。