使用volatile关键字和锁语句
本文关键字:语句 关键字 volatile 使用 | 更新日期: 2023-09-27 18:14:35
我在应用程序中得到了"对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
}
锁强制双方的内存屏障,所以是的,你的例子是线程安全的。
你几乎自己回答了:
ChangeValue(ref myVal); //Warning here
ChangeValue(ref myNonVolatileNumber); //no warning
编译后的ChangeValue()只有一个副本,其中的代码应该实现'volatile'行为。但是编译器(Jitter)在编译时不能预测所有的调用。唯一的选择是将每个 ref参数视为volatile,这将非常低效。
但是看看@Steven的评论,volatile
是无用的,应该避免。
可能不需要在您使用的地方使用volatile关键字。
This SO问题回答了所有应该使用volatile关键字的地方:
在c#中什么时候应该使用volatile关键字?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; }
}
,这里唯一的风险是后续代码访问该属性的私有成员。
在32位整数的情况下,或者甚至64位系统上的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();
}
}
}
这比标准锁好,因为它允许多个同时读。