Я ищу такие вещи, как изменение порядка кода, которые могут даже сломать код в случае нескольких процессоров.
Какие приемы использует процессор для оптимизации кода?
Ответы (4)
В Википедии есть довольно полный список методов оптимизации здесь.
Наиболее важным из них будет переупорядочение доступа к памяти.
В отсутствие ограждений памяти или инструкций по сериализации процессор может свободно переупорядочивать доступ к памяти. Некоторые процессорные архитектуры имеют ограничения на то, насколько они могут переупорядочиваться; Альфа известна тем, что является самой слабой (то есть той, которая может переупорядочивать больше всего).
Очень хорошее рассмотрение этой темы можно найти в исходной документации ядра Linux по адресу Documentation/memory-barriers.txt.
В большинстве случаев лучше всего использовать блокирующие примитивы из вашего компилятора или стандартной библиотеки; они хорошо протестированы, должны иметь все необходимые барьеры памяти и, вероятно, достаточно оптимизированы (оптимизация блокирующих примитивов сложна; даже эксперты могут иногда ошибаться).
Да, но в чем именно заключается ваш вопрос?
Однако, поскольку это интересная тема: приемы, которые используют компиляторы и процессоры для оптимизации кода, не должны ломать код даже при наличии нескольких процессоров при отсутствии в этом коде условий гонки. Это называется гарантией последовательной непротиворечивости: если в вашей программе нет условий гонки и все данные правильно заблокированы перед доступом, код будет вести себя так, как если бы он выполнялся последовательно.
Здесь есть действительно хорошее видео, в котором Херб Саттер говорит об этом:
http://video.google.com/videoplay?docid=-4714369049736584770
Это должен посмотреть каждый :)
Ответ DavidK правильный, однако также очень важно знать модель памяти для вашего языка/среды выполнения. Даже без условий гонки и с последовательной согласованностью и использованием мьютекса ваш код все равно может сломаться, когда данные кэшируются разными потоками, работающими в разных ядрах процессора. Некоторые языки, например, Java, гарантируют состояние данных между потоками при использовании блокировки мьютекса, но редко бывает достаточно просто гарантировать, что никакие два потока не могут получить доступ к данным одновременно. Вам необходимо правильно использовать мьютекс, чтобы убедиться, что среда выполнения языка синхронизирует состояние данных между двумя потоками. В java это делается путем синхронизации двух потоков на одном и том же объекте.
Вот хорошая страница, объясняющая проблему и то, как она решается в модели памяти javas.
http://gee.cs.oswego.edu/dl/cpj/jmm.html