Подскажите, пожалуйста, пример когда необходимо использовать класс Interlocked (желательно код). То есть не простые фразы из книг о необходимости и преимуществах использования этого класса, а конкретный примеры когда без Interlocked не работает, а с ним все хорошо.
Нужен этот класс тогда, когда есть несколько потоков и есть доступ к разделяемой переменной, которую они могут модифицировать.
Например ты запускаешь Parallel.ForEach
и желаешь видеть кол-во выполненных итераций, что бы видеть некоторый прогресс. Поэтому за пределами цикла ты объявил переменную cnt
.
Так вот, если в делегате ты будешь ее просто инкрементировать через ++
и выводить на консоль, то ты увидишь, что может быть бред из-за конкурентного доступа.
Для того, что бы это увидеть я сделал вот такой мини пример:
int cnt = 0;
var list = Enumerable.Range(0, 10000).ToList();
var options = new ParallelOptions() {MaxDegreeOfParallelism = 8};
Parallel.ForEach(list, options, (element) =>
{
var localCnt = Interlocked.Increment(ref cnt);
if(localCnt!= cnt)
Console.WriteLine("{0} {1} {2}",cnt, localCnt, Thread.CurrentThread.ManagedThreadId);
});
Как видно, мы в небольшом случае попадем в условие if
, когда несколько потоков параллельно модифицировали переменную и та переменная, которую мы локально себе сохранили не равна тому, что в данный момент содержится в cnt
.
Результат выводимый в консоль будет не стабильным, так как напрямую зависит от того, как ОС спланирует эти потоки. А может так случится, что звезды сойдутся и проблем не будет.
А если бы мы это делали через простой ++, то в LocalCnt мы рисковали получить то, чего не ожидали.
Чтение или запись логических значений отдельно , но "сравнение и обмен" выполняет как чтение, так и запись на один и тот же адрес, что означает, что целая транзакция не атомарная. Если несколько потоков могут записываться в это же место, вам нужно сделать всю транзакцию атомарной, используя класс Interlocked.
Пример:
Int32 val = 5;
Interlocked.CompareExchange(ref val, 90, 5);
Console.WriteLine(val);
Результат:
90
List<int> list = Enumerable.Range(1, 100).ToList();
int cnt = 0;
for (int i = 0; i < 10; i++)
{
cnt = 0;
Parallel.ForEach(list, (element) =>
{
for (int k = 0; k < 1000; k++)
{
cnt += element;
}
});
Console.Write(cnt);
Console.Write(" - ");
cnt = 0;
Parallel.ForEach(list, (element) =>
{
for (int k = 0; k < 1000; k++)
{
Interlocked.Add(ref cnt, element);
}
});
Console.WriteLine(cnt);
}
Вот такой код все таки в некоторых случаях показывает что без класса Interlocked сумма получается неправильная
Виртуальный выделенный сервер (VDS) становится отличным выбором
Не работает автопрокрутка (вертикальная) при отключеном автосдвиге(горизонтальной прокрутки при выделении с длинным названием item) горизонтальной...
Привествую, недавно увидел такой оператор ^=, но так и не нашел что он делает, применялся он к int, знаю что ^ это ислючения, но ^= да еще и для intЧТо...
При создании Table Unit выдаёт Предполагаемый лог UnitTest https://yadisk/d/KnbKKhyEYZq6Hw При этом, если в методе CreateRows будет отсутствовать строка r[i] = new Row(this,...