Помню, на курсе, который я проходил в колледже, одним из моих любимых примеров состояния гонки был случай, когда простой метод main()
запускал два потока, один из которых увеличивал общую (глобальную) переменную на единицу, а другой уменьшал ее. Псевдокод:
static int i = 10;
main() {
new Thread(thread_run1).start();
new Thread(thread_run2).start();
waitForThreads();
print("The value of i: " + i);
}
thread_run1 {
i++;
}
thread_run2 {
i--;
}
Затем профессор спросил, какова ценность i
после миллиона миллиардов прогонов. (Если, по сути, это когда-либо будет что-то отличное от 10.) Студенты, незнакомые с многопоточными системами, ответили, что в 100% случаев оператор print()
всегда будет сообщать i
как 10.
На самом деле это было неверно, поскольку наш профессор продемонстрировал, что каждый оператор увеличения/уменьшения был фактически скомпилирован (в сборку) как 3 оператора:
1: move value of 'i' into register x
2: add 1 to value in register x
3: move value of register x into 'i'
Таким образом, значение i
может быть 9, 10 или 11. (Я не буду вдаваться в подробности.)
Мой вопрос:
Я так понял (есть ли?), что набор физических регистров зависит от процессора. При работе с двухпроцессорными машинами (обратите внимание на разницу между двухъядерными и двухпроцессорными) каждый ЦП имеет собственный набор физических регистров? Я предполагал, что ответ положительный.
На однопроцессорной (многопоточной) машине переключение контекста позволяет каждому потоку иметь собственный виртуальный набор регистров. Поскольку на двухпроцессорной машине есть два физических набора регистров, не может ли это привести к еще большему потенциалу для условий гонки, поскольку вы можете буквально иметь два потока, работающих одновременно, в отличие от «виртуальной» одновременной работы на однопроцессорном компьютере? Машина с процессором? (Виртуальная одновременная работа в связи с тем, что состояния регистров сохраняются/восстанавливаются при каждом переключении контекста.)
Чтобы быть более конкретным - если вы запускали это на машине с 8 процессорами, каждый процессор с одним потоком, исключались ли условия гонки? Если вы расширите этот пример, чтобы использовать 8 потоков, на машине с двумя процессорами, каждый из которых имеет 4 ядра, увеличится или уменьшится вероятность условий гонки? Как операционная система предотвращает одновременный запуск step 3
ассемблерных инструкций на двух разных процессорах?