ATP>Да я в общем и не утверждаю что не нужны, я как раз интересуюсь в чем здесь тонкие моменты, зачем нужны короче Они нужны для обеспечения корректного взаимного упорядочивания обращений к памяти. Основной паттерн такой — производитель записывает данные в объект, потом записывает указатель на этот объект в разделяемую переменную, потом потребитель считывает указатель на объект из разделяемой переменной, потом считывает данные из объекта. Этот паттерн используется и в очередях производитель-потребитель, и в ленивом многопоточном синглтоне, и в разделяемом хэш-мапе. В многопоточном окружении *не* гарантируется последовательная консистентность (sequential consistency), т.е. другие потоки могут видеть обращения к памяти не так как они записаны в программе. Причин для неправильного упорядочивания есть 2: первая — переупорядочивания компилятором, вторая — переупорядочивания процессором. А результате этих переупорядочиваний мы можем получить следующие неприятные ситуации: производитель может записать указатель на объект в разделяемую переменную ещё до записи в него данных и/или потребитель может считать данные из объекта ещё до считывания указателя на объект. В любом случае мы получаем UB. В алгоритмах многопоточной синхронизации необходимо обеспечивать требуемый взаимный порядок обращений к памяти явно. Для этого служат барьеры памяти (memory barrier, memory fence), в C++0x будет стандартное АПИ для этого, пока же приходится довольствоваться компиляторо-зависимым средствами (в частности _ReadWriteBarrier() подавляет переупорядочивания компилятором вокруг себя). Вот простой пример (в терминах C++0x):
std::memory_order_release гарантирует (не формально), что все предыдущие обращения к памяти будут завершены до данного сохранения. std::memory_order_acquire гарантирует, что все последующие обращения к памяти будут начаты только после завершения данной загрузки. Недавно я отвечал на подобный вопрос: http://software.intel.com/ru-ru/forums/showthread.php?t=72142 (там есть примеры барьеров памяти для MSVC, gcc, SUN cc). В частности вот пример кода, на котором вы можете наблюдать переупорядочивание обращений процессором на своём многоядерном процессоре х86: http://software.intel.com/ru-ru/forums/showpost.php?p=110773 |