Являются ли барьеры памяти необходимыми для подсчета атомных ссылок совместно используемыми неизменяемыми данными?
У меня есть некоторые неизменные структуры данных, с которыми я бы хотел справиться, используя подсчет ссылок, разделяя их по потокам в системе SMP.
Вот что выглядит код выпуска:
void avocado_release(struct avocado *p)
{
if (atomic_dec(p->refcount) == 0) {
free(p->pit);
free(p->juicy_innards);
free(p);
}
}
Требуется ли atomic_dec
в нем барьер памяти? Если да, то какой барьер памяти?
Дополнительные примечания: приложение должно работать на PowerPC и x86, поэтому приветствуется вся информация, относящаяся к конкретному процессору. Я уже знаю о атомных сборках GCC. Что касается неизменности, то refcount является единственным полем, которое изменяется в течение продолжительности объекта.
Ответы
Ответ 1
На x86 он превратится в инструкцию по сборке с префиксом блокировки, например LOCK XADD
.
Будучи единой инструкцией, она не прерывается. В качестве добавленного "feauture" префикс блокировки приводит к полному барьеру памяти:
"... заблокированные операции сериализуют все выдающиеся операции загрузки и хранения (то есть ждут их завершения)."... "Заблокированные операции являются атомарными по отношению ко всем другим операциям памяти и всем видимым извне событиям. Доступ к команде и выбор таблицы страниц могут передавать заблокированные инструкции. Заблокированные инструкции могут использоваться для синхронизации данных, написанных одним процессором и считанных другим процессором". - Руководство разработчика программного обеспечения для архитектуры Intel® 64 и IA-32, глава 8.1.2.
На самом деле барьер памяти реализуется как манекен LOCK OR
или LOCK AND
в .NET и JAVA JIT на x86/x64.
Таким образом, у вас есть полный забор на x86 в качестве дополнительного бонуса, нравится вам это или нет.:)
В КПП это другое. Пара LL/SC - lwarx
и stwcx
- с вычитанием внутри можно использовать для загрузки операнда памяти в регистр, вычесть его, затем либо записать обратно, если в целевое местоположение не было другого хранилища, либо повторить весь цикл, если он был. LL/SC может быть прерван.
Это также не означает автоматический полный забор.
Это никоим образом не скомпрометирует атомарность счетчика.
Это просто означает, что в случае x86 вы также получаете забор, "бесплатно" .
В PPC можно вставить полный забор, испустив (lw)sync
.Суб >
В общем, явные барьеры памяти не нужны, чтобы атомный счетчик работал правильно.
Ответ 2
Важно различать атомарные обращения (которые гарантируют, что чтение/изменение/запись значения выполняются как один атомный блок) и переупорядочение памяти.
Пункты памяти препятствуют переупорядочению чтений и записи, а переупорядочение полностью ортогонально к атомарности. Например, на PowerPC, если вы реализуете наиболее эффективный атомный приращение, это не помешает переупорядочению. Если вы хотите предотвратить переупорядочение, вам понадобится инструкция lwsync или sync или какой-либо эквивалентный высокоуровневый (С++ 11?) Барьер памяти.
Утверждается, что "нет возможности компилятора переупорядочить вещи проблематичным образом" кажутся наивными, как общие утверждения, поскольку оптимизация компилятора может быть довольно неожиданным и потому, что процессоры (в частности, PowerPC/ARM/Alpha/MIPS) агрессивно меняют порядок операций с памятью.
Когерентный кеш не спасет вас. См. http://preshing.com/, чтобы увидеть, как действительно работает переупорядочение памяти.
В этом случае, однако, я считаю, что ответ заключается в том, что никаких барьеров не требуется. Это связано с тем, что для этого конкретного случая (подсчета ссылок) нет необходимости в отношении отношения между счетчиком ссылок и другими значениями в объекте. Единственное исключение - когда счетчик ссылок достигает нуля. В этот момент важно обеспечить, чтобы все обновления из других потоков были видны текущему потоку, поэтому может потребоваться барьер считывания.
Ответ 3
Намерены ли вы реализовать свой собственный atomic_dec
или вам просто интересно, будет ли система, работающая под управлением, вести себя так, как вы хотите?
Как правило, поставляемые в комплекте атомарные устройства увеличения/уменьшения уровня будут применяться к любым барьерам памяти, чтобы делать правильные действия. Вы, как правило, не должны беспокоиться о барьерах памяти, если вы не делаете что-то нелепо, как реализовать свои собственные блокированные структуры данных или библиотеку STM.