使用volatile关键字和lock语句

时间:2011-11-15 16:53:00

标签: c# .net multithreading volatile

我在应用程序中得到“对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
}

4 个答案:

答案 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关键字的地方:

When should the volatile keyword be used in C#?

答案 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();
        }
    }
}

这比标准锁更好,因为它允许多个同时读取。