Барьеры памяти и параллельные расширения - PullRequest
1 голос
/ 13 марта 2012

Нужно ли беспокоиться о MemoryBarriers при использовании параллельных расширений?

Редактировать - для уточнения, поскольку исходный вопрос был открытым: (ответ @xanatos был тем, который я искал)

Чтобы привести конкретный пример: предположим, что я использую Parallel.ForEachи каждая итерация устанавливает значение свойства в классе (каждая итерация устанавливает свое собственное определенное свойство, никакие две итерации не устанавливают значение одного и того же свойства).В том же потоке, который называется Parallel.ForEach, я получаю доступ к свойствам, которые были установлены из Parallel.ForEach.

class Program
{
  static void Main(string[] args)
  {
    var t = new Test();
    t.InitializePropertiesInParallel();
    var a = t.PropA; // Could never be 0?
    var b = t.PropB; // Could never be 0?
  }
}

public class Test
{
  public int PropA { get; set; }
  public int PropB { get; set; }

  public void InitializePropertiesInParallel()
  {
    var initializers = new List<Action<int>>()
    {
      i => PropA = i,
      i => PropB = i
    };

    initializers.AsParallel().ForAll(a => a(1));
  }
}

Ответы [ 2 ]

2 голосов
/ 15 марта 2012

Помните здесь одну вещь: аннулирование строки кэша. Это сложная тема, но здесь есть отличная статья MSDN .

Суть этого конкретного примера в том, что, поскольку вы модифицируете один и тот же экземпляр объекта из двух разных потоков, даже если вы не касаетесь одного и того же места в памяти, вы будете касаться одной и той же строки кэша и поэтому, когда первый поток в процессоре 1 изменяет память, кэш будет очищен и обновлен, прежде чем процессор 2 сможет снова выполнить чтение / запись в него.

Тем не менее, опять же, учитывая ваш конкретный пример с двумя опорами, это микрооптимизация и абсолютно не о чем беспокоиться. Просто что-то, о чем нужно знать, если вы будете экстраполировать это.

1 голос
/ 13 марта 2012

Если каждому работнику не нужны данные, подготовленные другими работниками (поэтому нет ситуации, когда работник 1 пишет A, а работник 2 читает A), MemoryBarrier не требуется. Когда все задачи завершаются, появляется Wait, который действует как MemoryBarrier (в конце концов, даже если вы его не видите, где-то есть конструкция синхронизации, которая ждет завершения всех рабочих)

...