Барьеры памяти и параллельные расширения

Нужно ли беспокоиться о 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));
  }
}

person dugas    schedule 13.03.2012    source источник
comment
Это зависит от того, что вы делаете параллельно.   -  person SLaks    schedule 13.03.2012
comment
Пожалуйста, дополните. В нынешнем виде ваш вопрос несколько открыт.   -  person Robert Harvey    schedule 13.03.2012
comment
Доработано по запросу.   -  person dugas    schedule 14.03.2012


Ответы (2)


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

person xanatos    schedule 13.03.2012

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

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

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

person Drew Marsh    schedule 15.03.2012
comment
+1 Важно отметить, что это проблема производительности, а не корректности данных. - person xanatos; 15.03.2012