Когда использовать 'энергозависимый' или 'Поток. MemoryBarrier ()' в ориентированном на многопотоковое исполнение коде блокировки? (C#)

Необходимо реализовать Выполнимый, но если Вы работаете на Java 5 или выше, Вы не должны запускать его с new Thread, но использовать ExecutorService вместо этого. Для получения дополнительной информации см.: , Как реализовать простую поточную обработку в Java.

16
задан Alex 25 August 2009 в 20:05
поделиться

3 ответа

Вы используете volatile / Thread.MemoryBarrier () , если хотите получить доступ к переменной в потоках без блокировки.

Атомарные переменные как, например, int , всегда читаются и записываются целиком одновременно. Это означает, что вы никогда не получите половину значения до того, как другой поток изменит его, а другую половину - после его изменения. Из-за этого вы можете безопасно читать и записывать значение в разных потоках без синхронизации.

Однако компилятор может оптимизировать некоторые операции чтения и записи, что можно предотвратить с помощью ключевого слова volatile . Если, например, у вас есть такой цикл:

sum = 0;
foreach (int value in list) {
   sum += value;
}

Компилятор может фактически выполнять вычисления в регистре процессора и записывать значение в переменную sum только после цикла.

20
ответ дан 30 November 2019 в 16:24
поделиться

Что не так с

private static readonly object syncObj = new object();
private static int counter;

public static int NextValue()
{
    lock (syncObj)
    {
        return counter++;
    }
}

?

Это делает за вас все необходимые блокировки, барьеры памяти и т.д. Он хорошо понятен и более читабелен, чем любой пользовательский код синхронизации, основанный на volatile и Thread.MemoryBarrier () .


EDIT

Я не могу придумать сценарий, в котором Я бы использовал volatile или Thread.MemoryBarrier () . Например,

private static volatile int counter;

public static int NextValue()
{
    return counter++;
}

не эквивалентно приведенному выше коду и не потокобезопасный ( volatile не делает ++

В таком случае:

private static volatile bool done;

void Thread1()
{
    while (!done)
    {
        // do work
    }
}

void Thread2()
{
    // do work
    done = true;
}

(который должен работать) я бы использовал ManualResetEvent , чтобы сигнализировать о завершении Thread2.

10
ответ дан 30 November 2019 в 16:24
поделиться

В основном, если вы используете какой-либо другой вид синхронизации, чтобы сделать ваш код потокобезопасным, то в этом нет необходимости.

Большинство механизмов блокировки (включая блокировку) автоматически подразумевают память барьер, чтобы несколько процессоров могли получать правильную информацию.

Volatile и MemoryBarrier в основном используются в сценариях без блокировки, когда вы пытаетесь избежать потери производительности от блокировки.

Изменить: Вы должны прочитать ] эта статья Джо Даффи о модели памяти CLR 2.0, она многое проясняет (если вам действительно интересно, вы должны прочитать ВСЮ статью Джо Даффи, который в целом является наиболее опытным специалистом в области параллелизма. NET)

10
ответ дан 30 November 2019 в 16:24
поделиться
Другие вопросы по тегам:

Похожие вопросы: