Использование ключевого слова volatile и оператора блокировки - PullRequest
1 голос
/ 15 ноября 2011

Я получаю предупреждение "ссылка на изменчивое поле не будет рассматриваться как изменчивое" в приложении.Я понимаю, почему.

В качестве простого примера приведенный ниже код сделает проблему проблемной, даже если я получу предупреждение до сих пор?

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 ]

2 голосов
/ 15 ноября 2011

Блокировка вызывает барьеры памяти с обеих сторон, так что да, ваш пример является поточно-ориентированным.

1 голос
/ 15 ноября 2011

Вероятно, нет необходимости использовать ключевое слово volatile в том месте, которое вы использовали.

Этот SO-вопрос отвечает, где все должны использоваться ключевое слово volatile, если вообще:

Когда следует использовать ключевое слово volatile в C #?

1 голос
/ 15 ноября 2011

Вы почти отвечаете сами:

ChangeValue(ref myVal); //Warning here
ChangeValue(ref myNonVolatileNumber); //no warning

Существует только 1 копия скомпилированного ChangeValue (), код внутри должен реализовывать поведение 'volatile'.Но компилятор (Jitter) не может предсказать все вызовы при компиляции.Единственный вариант - рассматривать каждый параметр ref как volatile, что будет очень неэффективно.

Но, смотри @ комментарий Стивена, volatile так же бесполезен и его следует избегать.

0 голосов
/ 16 ноября 2011

Что было бы не так с

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

Это лучше, чем стандартная блокировка, поскольку она допускает многократное одновременное чтение.

...