Локальная переменная внутри параллельных циклов потокобезопасность

У меня есть переменная (cnt) внутри вложенный parallel.foreach, Я запускаю эту программу и, видимо, она работает хорошо. Кто-нибудь знает, что этот код действительно потокобезопасен? Можно ли определить переменную внутри parallel петли?

Спасибо.

    object obj = new object();
    int total=0;

    Parallel.For(0, 2, i =>
    {
        Parallel.For(0, 1000000, j =>
        {
            int cnt = 0;
            if ((arr[i, j] % 2) == 0)
            {
                Interlocked.Increment(ref cnt);
            }
            lock (obj)
            {
                total= total+ (cnt / 2);
            }
        });
    });

2 ответа

Решение

Этот код является потокобезопасным - единственные общие данные (total) правильно синхронизирован. Это потокобезопасно даже без использования Interlocked.Increment (т.е. до вашего редактирования).

Однако это не эффективно.

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

int total=0;
Parallel.For(0, 2, 
{
    Parallel.For(0, 1000000, 
      local => 0,
      (j, state, local) =>
      {
        if ((arr[i, j] % 2) == 0)
        {
           ++local;
        }
        return local;
      },
      local => Interlocked.Increment(ref total, local)
    );
});

Этот код действительно безопасен, потому что lock Заявление выступает в качестве полной операции ограждения. Это гарантирует, что операция приращения является атомарной и не будет подвергаться гонкам из других потоков.

Другие вопросы по тегам