Атомарный доступ к общей памяти - PullRequest
9 голосов
/ 06 января 2012

У меня есть общая память между несколькими процессами, которая определенным образом пересекает память.Пример:

DataBlock {
int counter;
double value1;
double ...    }

Я хочу, чтобы счетчик обновлялся / увеличивался атомарно.И для освобождения памяти произойдет по этому адресу.Например, если бы я не использовал разделяемую память, это было бы что-то вроде

std::atomic<int> counter;
atomic_store(counter, newvalue, std::memory_order_release); // perform release     operation on the affected memory location making the write visible to other threads

Как мне добиться этого для произвольной ячейки памяти (интерпретируется как счетчик DataBlock> выше).Я могу гарантировать, что адрес выровнен в соответствии с требованиями архитектуры (x86 linux)

  1. Сделать обновление атомарным - как?(т.е. atomicupdate (addr, newvalue))
  2. Синхронизация памяти для многоядерности ((например, memorysync (addr)) - единственный способ, который я вижу, это использование std :: atomic_thread_fence (std :: memory_order_release) - но это будет«установить порядок синхронизации памяти ВСЕХ атомарных и расслабленных атомных хранилищ» - это для меня излишне - я просто хочу синхронизировать расположение счетчика.Цени любые мысли.

Ответы [ 4 ]

9 голосов
/ 06 января 2012

Я не могу ответить с правами здесь, но я могу дать связанную информацию, которая может помочь.

  1. Мьютексы могут создаваться в общей памяти и / или создаваться как перекрестные процессы. У Pthread есть специальный флаг создания, я не могу вспомнить, использует ли он разделяемую память, или вы затем делите дескриптор. Linux "futex" может напрямую использовать разделяемую память (обратите внимание, что адрес пользователя может отличаться, но реальный адрес должен быть тем же)

  2. Аппаратная атомика работает с памятью, а не с переменными процесса. То есть вашей микросхеме все равно, какие программы изменяют переменные, поэтому атомы самого низкого уровня, естественно, будут кросс-процессными. То же относится и к заборам.

  3. C ++ 11 не может определить атомарность между процессами. Однако, если они свободны от блокировки (установите флажок), трудно понять, как компилятор мог бы реализовать их так, чтобы кросс-процесс не работал. Но вы сильно поверите в свою цепочку инструментов и конечную платформу.

  4. Зависимость процессора гарантирует также отслеживание адресов реальной памяти, поэтому до тех пор, пока ваша программа будет правильной в многопоточном формате, она также должна быть правильной в многопроцессной форме (с точки зрения видимости).

  5. Kerrek верен, абстрактная машина на самом деле не упоминает несколько процессов. Тем не менее, его детали синхронизации написаны таким образом, что они в равной степени применимы к межпроцессным, как и к многопоточности. Это относится к # 3: компилятору было бы трудно облажаться.

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

Самый большой вопрос - можно ли просто выделить атомик в общей памяти (размещение нового) и работать. Очевидно, это будет работать только в том случае, если это настоящий аппаратный атом. Однако я предполагаю, что с качественным компилятором / библиотекой атомарность C ++ должна работать в общей памяти.

Весело проверяйте поведение. :)

4 голосов
/ 06 января 2012

Поскольку вы работаете в Linux, вы можете использовать gcc атомарный встроенный __sync_fetch_and_add() по адресу для counter ... в соответствии с gcc-документацией по атомарным встроенным , это также будет реализовывать полное ограничение памяти, а не операцию освобождения, но, поскольку вы действительно хотите выполнить операцию чтения-изменения-записи, а не просто загрузку (т. е. увеличение счетчика - это не просто загрузка, но вы должны прочитать, затем измените и, наконец, запишите значение), забор полной памяти будет лучшим выбором для обеспечения правильного упорядочения памяти для этой операции.

0 голосов
/ 27 июня 2019

Я смотрю на стандартный черновик N4820 [atomics.lockfree], и ​​он говорит:

4 [Note: Operations that are lock-free should also be address-free. That is, atomic operations on the same
memory location via two different addresses will communicate atomically. The implementation should not
depend on any per-process state. This restriction enables communication by memory that is mapped into a
process more than once and by memory that is shared between two processes. — end note]

, поэтому, если вы задаете таргетинг на адрес, предварительное условие не блокируется, и это можно проверитьпо std :: atomic.

однако я не уверен, как должен быть создан объект atomic.Достаточно ли этого, чтобы поместить объект в общую память?я не нашел никакой спецификации на это использование, хотя я вижу такое использование кода на github.

0 голосов
/ 06 января 2012

Вы можете использовать механизм блокировки и ожидания для увеличения счетчика. Boost Library предоставляет механизм блокировки и ожидания. проверьте эту ссылку для ссылки

...