Необходимы ли барьеры памяти для атомного подсчета ссылок совместно используемых неизменяемых данных? - PullRequest
12 голосов
/ 08 апреля 2010

У меня есть несколько неизменных структур данных, которыми я хотел бы управлять с помощью счетчиков ссылок, разделяя их между потоками в системе 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 - это поле only , которое изменяется в течение всего срока действия объекта.

Ответы [ 3 ]

11 голосов
/ 09 апреля 2010

На 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 вы также получаете забор «бесплатно».
На КПП можно вставить полный забор, выдав инструкцию (lw)sync .

В общем, явные барьеры памяти не нужны для правильной работы атомного счетчика.

4 голосов
/ 18 февраля 2015

Важно различать атомарный доступ (который гарантирует, что чтение / изменение / запись значения выполняется как одна атомная единица) и переупорядочение памяти.

Барьеры памяти предотвращают переупорядочение операций чтения и записи, и переупорядочение полностью ортогонально атомарности. Например, в PowerPC, если вы реализуете наиболее эффективный атомарный инкремент, то это не помешает переупорядочению. Если вы хотите предотвратить переупорядочение, вам нужна инструкция lwsync или sync или какой-либо эквивалентный высокоуровневый (C ++ 11?) Барьер памяти.

Утверждения о том, что «нет никакой возможности перекомпоновать компилятор проблемным способом», кажутся наивными общими утверждениями, потому что оптимизация компилятора может быть довольно неожиданной и потому что процессоры (в частности, PowerPC / ARM / Alpha / MIPS) агрессивно переупорядочивают операции с памятью .

Связанный кеш тоже вас не спасет. См. http://preshing.com/, чтобы увидеть, как на самом деле работает переупорядочение памяти.

Однако в этом случае я считаю, что ответ заключается в том, что никаких барьеров не требуется. Это связано с тем, что для этого конкретного случая (подсчета ссылок) нет необходимости в связи между количеством ссылок и другими значениями в объекте. Единственное исключение - когда счетчик ссылок достигает нуля. На этом этапе важно убедиться, что все обновления из других потоков видны текущему потоку, поэтому может потребоваться барьер для чтения-чтения .

2 голосов
/ 08 апреля 2010

Собираетесь ли вы реализовать свой собственный atomic_dec или вам просто интересно, будет ли системная функция работать так, как вы хотите?

Как правило, предоставляемые системой средства увеличения / уменьшения атома будут применяться независимо от того, какие барьеры памяти необходимы для правильной работы. Как правило, вам не нужно беспокоиться о барьерах памяти, если вы не делаете что-то дурацкое, например, реализуете свои собственные структуры данных без блокировки или библиотеку STM.

...