Гарантирует ли Interlocked видимость другим потокам в C # или мне все еще нужно использовать volatile? - PullRequest
6 голосов
/ 19 марта 2010

Я читал ответ на подобный вопрос , но я все еще немного сбит с толку ... У Авеля был отличный ответ, но в этой части я не уверен

... объявление переменной volatile делает ее изменчивой для каждого доступ. Невозможно заставить это поведение любым другим способом, следовательно, изменчивым не может быть заменено блокированным. Это необходимо в сценариях, где другие библиотеки, интерфейсы или аппаратное обеспечение может получить доступ к вашей переменной и обновить его в любое время или нужно больше последняя версия.

Гарантирует ли Interlocked видимость атомарной операции для всех потоков, или мне все еще нужно использовать ключевое слово volatile для значения, чтобы гарантировать видимость изменения?

Вот мой пример:

volatile int value = 100000; // <-- do I need the volitile keyword
// ....

public void AnotherThreadMethod()
{
 while(Interlocked.Decrement(ref value)>0)
 {
  // do something
 }
}


public void AThreadMethod()
{
 while(value > 0)
 {
  // do something
 }
}

Обновление:
Я был плохим спортом, и я изменил оригинальный пример, так что вот снова:

public class CountDownLatch
{
    private volatile int m_remain; // <--- do I need the volatile keyword here?
    private EventWaitHandle m_event;

    public CountDownLatch(int count)
    {
        Reset(count);
    }

    public void Reset(int count)
    {
        if (count < 0)
            throw new ArgumentOutOfRangeException();
        m_remain = count;
        m_event = new ManualResetEvent(false);
        if (m_remain == 0)
        {
            m_event.Set();
        }
    }

    public void Signal()
    {
        // The last thread to signal also sets the event.
        if (Interlocked.Decrement(ref m_remain) == 0)
            m_event.Set();
    }

    public void Wait()
    {
        m_event.WaitOne();
    }
}

Ответы [ 2 ]

5 голосов
/ 19 марта 2010

Им не * нужна ** волатильность, потому что вы никогда не проверяете значение блокированной переменной. Вместо этого вы всегда проверяете значение , возвращаемое с помощью операции (ов) с блокировкой. Смешанные взаимосвязанные операции и обычное присваивание / сравнение всегда приводят к неправильному коду.

Я не уверен, каково намерение функции Reset (), но этот фрагмент кода не помещается в примитив между потоками: вы присваиваете m_remain, вы проверяете значение m_remain напрямую, это довольно плохо. Я настоятельно рекомендую вам снять его: не только он реализован неправильно, но я очень сомневаюсь, что семантика «сброса» счетчика среднего срока службы необходима. Оставьте все просто: ctor (переместите код из Reset в него) Signal и Wait - это только три необходимых оператора, и они верны, как и сейчас.

Обновлено После того, как вы отредактировали код.

Игнорируя тот факт, что вы не должны смешивать два, если вы в конечном итоге смешаете их, тогда да, энергозависимость все еще необходима. Volatile в первую очередь относится к коду IL и коду JIT, сгенерированному для обеспечения того, чтобы значение всегда считывалось из фактической ячейки памяти и не происходила оптимизация, например, переупорядочение кода. Тот факт, что несвязанный фрагмент кода обновляет значение с помощью взаимосвязанных операций, не влияет на другие части, которые читают значение. Без атрибута volatile компилятор / JIT может по-прежнему генерировать код, который игнорирует записи, которые происходят где-то еще, не имеет значения, если записи заблокированы или прямое назначение.

Кстати, существуют допустимые шаблоны, которые смешивают обычные операции чтения и блокированные операции, но обычно они включают Interlocked.CompareExchange и такие действия: чтение текущего состояния, выполнение некоторых вычислений на основе текущего состояния, попытка заменить состояние как сравнение с блокировкой -exchange: если все в порядке, если нет, отбросьте результат вычисления и вернитесь к шагу 1.

2 голосов
/ 23 марта 2010

Я думаю, что System.Threading.Thread.VolatileRead (ref myVariable) может быть тем, что вы ищете. Используемый совместно с Interlocked.Increment, он может использоваться для гарантии того, что изменения являются атомарными, а значения, которые вы читаете, являются самыми последними.

...