Один аспект, который может быть рассмотрен при наличии проблем / повышенных усилий в отношении тестирования, заключается в том, есть ли возможность изменить тестируемую программу каким-либо образом, что поможет в тестировании без существенного увеличения сложности кода. [110 ]
В этом случае есть ли возможность заменить вызовы exit () на коды возврата ошибок из функций, чтобы вызывающие абоненты могли выполнять такие действия, как приведение в порядок или состояние журнала, перед тем, как фактически завершить работу? Если это так, то это одновременно упрощает тестирование и, вероятно, упростит поиск ошибок, когда код фактически используется в выпуске / производстве, так как может быть довольно сложно понять, почему программа просто «взлетает» и умирает, особенно если код спрятан в библиотечной функции!
volatile
только силы Ваш код для перечитывания значения это не может управлять, где значение читается из. Если значение было недавно считано Вашим кодом затем, это, вероятно, будет в кэше, в этом случае энергозависимый вынудит это быть перечитанным от кэша, НЕ из памяти.
нет большого количества инструкций по когерентности кэш-памяти в x86. Существуют инструкции по упреждающей выборке как prefetchnta
, но это не влияет на заказывающую память семантику. Это раньше реализовывалось путем обеспечения значения к кэшу L1, не загрязняя L2, но вещи более сложны для современных проектов Intel с большим общим содержащий кэш L3.
x86 центральные процессоры используют вариацию на протокол MESI (MESIF для Intel, MOESI для AMD) для хранения их кэшей когерентными друг с другом (включая частные кэши L1 различных ядер). Ядро, которое хочет записать строку кэша, должно вынудить другие ядра делать недействительным свою копию ее, прежде чем она сможет изменить свою собственную копию от Общего до Измененного состояния.
<час> Вам не нужны никакие инструкции по забору (как MFENCE), чтобы произвести данные в одном потоке и использовать его в другом на x86, потому что загрузки/хранилища x86 имеют , получают/выпускают семантику встроенный. Вам действительно нужен MFENCE (полный барьер) для получения последовательной непротиворечивости. (Предыдущая версия этого ответа предположила, что clflush
был необходим, который является неправильным).
действительно необходимо предотвратить время компиляции, переупорядочив , потому что модель памяти C++ слабо заказана. volatile
старый, плохой способ сделать это; C++ 11 станд.:: атомарный намного лучший способ написать свободный от блокировок код.
Когерентность кэша гарантируется между ядрами из-за протокола MESI, используемого x86 процессорами. Только необходимо волноваться о когерентности памяти при контакте с внешним оборудованием, которое может получить доступ к памяти, в то время как данные все еще располагают в кэшах ядер. Не похож это - Ваш случай здесь, тем не менее, так как текст предполагает, что Вы программируете в пространстве пользователя.
Вы не должны волноваться о когерентности кэш-памяти. Аппаратные средства будут заботиться об этом. То, о чем Вы, возможно, должны волноваться, является проблемами производительности из-за той когерентности кэш-памяти.
, Если core#1 пишет в переменную, которая делает недействительным все другие копии строки кэша в других ядрах (потому что это должно добраться эксклюзивное владение из строки кэша прежде, чем фиксировать хранилище). Когда core#2 считает ту же самую переменную, он будет отсутствовать в кэше (если core#1 уже не записал его обратно до общего уровня кэша).
, Так как вся строка кэша (64 байта) должна быть считана из памяти (или записана обратно к общему кэшу и затем чтению core#2), это будет иметь некоторую стоимость производительности. В этом случае это неизбежно. Это - желаемое поведение.
<час>проблема состоит в том, что, когда у Вас есть несколько переменных в той же строке кэша, процессор мог бы провести дополнительное время, сохраняя кэши в синхронизации, даже если ядра читают/пишут различные переменные в той же строке кэша.
, Которые стоят, может избежаться путем проверки, что те переменные не находятся в той же строке кэша. Этот эффект известен как Ложь, Совместно использующая , так как Вы вынуждаете процессоры синхронизировать значения объектов, которые на самом деле не совместно используются потоками.
Энергозависимый не сделает этого. В C++, энергозависимом только, влияет что оптимизация компилятора, такая как хранение переменной в регистре вместо памяти или удаления его полностью.
Вы не указывали, какой компилятор Вы используете, но если Вы находитесь на окнах, смотрите на эта статья здесь . Также смотрите на доступные функции synchronization здесь . Вы могли бы хотеть отметить, что в общем volatile
недостаточно, чтобы сделать то, что Вы хотите, чтобы это сделало, но под VC 2005 и 2008, существует нестандартная семантика, добавленная к нему, которые добавляют подразумеваемые барьеры памяти вокруг чтения и записей.
, Если Вы хотите вещи быть портативными, Вы собираетесь иметь намного более твердую дорогу перед Вами.
Существует ряд статей, объясняющих современные архитектуры памяти здесь , включая кэши Intel Core2 и намного более современные темы архитектуры.
Статьи очень читаемы и хорошо проиллюстрированы. Наслаждайтесь!
Herb Sutter казался просто , предлагают , что любые две переменные должны находиться на отдельных строках кэша. Он делает это в своей параллельной очереди с дополнением между его блокировками и указателями узла.
Редактирование: при использовании компилятора Intel или GCC можно использовать атомарный builtins, которые, кажется, прилагают все усилия для вытеснения кэша, если это возможно.
В вашем вопросе есть несколько подвопросов, поэтому я отвечу на них, насколько мне известно. [1274 В настоящее время в C ++ нет переносимого способа реализации взаимодействий без блокировки. Предложение C ++ 0x решает эту проблему, представляя библиотеку atomics.
Ниже приводится хорошая статья, посвященная использованию volatile
с многопоточными программами.
Энергозависимость почти бесполезна для многопоточного программирования .