Никогда не предполагайте, что какая-либо операция по потоку по умолчанию - так как это не так.
Для примера рассмотрим следующую Types
:
public class A
{
public B b;
}
public struct B
{
public int a;
public int b;
public int c;
public int d;
}
и следующий метод:
public static void Func(B b)
{
Console.WriteLine($"{b.a}, {b.b}, {b.c}, {b.d}");
}
Если вы будете иметь следующий Main
метод и паузы консоли один раз в то время:
A a = new A();
new Thread(() =>
{
while (true)
{
a.b.a = 5;
a.b.b = 5;
a.b.c = 5;
a.b.d = 5;
}
}).Start();
while (true)
{
a.b.a = 1;
a.b.b = 2;
a.b.c = 3;
a.b.d = 4;
Func(a.b);
}
вы увидите, что некоторые из structs
смешиваются между 1
, 2
, 3
, 4
и 5
.
Любое примитивное действие на типе более 32 бит не является атомарным на машине x86
, то же, что и на 64 бит и x64
.
Не то, что это означает, что вы можете использовать любую операцию на int
будет безопасным, например:
манипулируя int
от многоядерного процессора, скажем, ++someInt
от 2-х потоков, даже если он компилирует inc
x86
инструкция может случиться.
someInt
является 9.
- сердечник 1 принимает
someInt
из своего кэша.
- core 2 принимает
someInt
из кеша.
- Ядро 1 увеличивает значение, которое оно имеет до 10, и сохраняет его в кеш.
- Ядро 2 увеличивает значение, которое оно имеет до 10, и сохраняет его в кеш.
someInt
был увеличен в два раза, но это равняется 10.
Использование Interlocked
вместо, например, будет компилировать lock inc
, который заблокирует шину и убедитесь, что ядро имеет исключительное право собственности соответствующего кэша.
Downvoter, пожалуйста, объясните, чтобы я мог улучшить свой ответ. –
Согласен. У меня тоже нет ни одного аргумента. Возможно, мы ошибаемся, но это нужно уточнить. –