Общая память или mmap-Linux C / C++ IPC

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

Мне очень удобно делать это в программировании сокетов. Чтобы сделать связь между сервером и клиентами быстрее и уменьшить количество копий, я хочу попробовать использовать общую память(shm) или mmaps.

ОС является RHEL 64bit.

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

Спасибо за ответы. Я хотел добавить, что сервер (сервер рыночных данных) обычно будет получать многоадресные данные, что приведет к "отправке" около 200 000 структур в секунду "клиентам", где каждая структура составляет примерно 100 байт. Превосходит ли реализация shm_open / mmap сокеты только для больших блоков данных или большого объема небольших структуры тоже ?

4 ответов


я хотел бы использовать mmap вместе с shm_open на карте памяти в виртуальное адресное пространство процессов. Это относительно прямо и чисто:

  • определения общей памяти сегмент с какой-то символикой имя, что-то вроде "/myRegion"
  • С shm_open открыть файл дескриптор на этой области
  • С ftruncate вы увеличиваете сегмент до нужного размера
  • С mmap сопоставить его в свой адрес космос!--16-->

на shmat и интерфейсы Co имеют (по крайней мере, исторически) недостаток, что они могут иметь ограничение в максимальном объеме памяти, который вы можете отобразить.

затем все инструменты синхронизации потоков POSIX (pthread_mutex_t, pthread_cond_t, sem_t, pthread_rwlock_t, ...) имеют интерфейсы инициализации, которые позволяют использовать их в общем контексте процесса. Все современные дистрибутивы Linux поддерживают.

предпочтительно ли это или нет над розетками? Производительность мудрая, это может немного изменить ситуацию, так как вам не нужно копировать вещи вокруг. Но главное, я думаю, было бы то, что, как только вы инициализировали свой сегмент, это концептуально немного проще. Чтобы получить доступ к элементу, вам просто нужно заблокировать общий замок, прочитать данные и снова разблокировать замок.

как предполагает @R, Если у вас есть несколько читателей pthread_rwlock_t вероятно, лучшая структура блокировки для использования.


однажды я реализовал библиотеку IPC с использованием сегментов общей памяти; это позволило мне избежать копирования (вместо копирования данных из памяти отправителя в пространство ядра, а затем из пространства ядра в память получателя, я мог бы напрямую копировать из памяти отправителя в память получателя).

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

результаты были хороши только для действительно больших сообщений (скажем, более нескольких мегабайт), если вы работаете с маленькими буферами, сокеты unix-самая оптимизированная вещь, которую вы можете найти, если вы не хотите написать модуль ядра.


помимо того, что уже было предложено, я хотел бы предложить другой метод: локальная Многоадресная рассылка узла/интерфейса IPv6, т. е. многоадресная рассылка, ограниченная интерфейсом loopback. http://www.iana.org/assignments/ipv6-multicast-addresses/ipv6-multicast-addresses.xml#ipv6-multicast-addresses-1

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

вместо передачи необработанных структур вы должны использовать надежную структуру данных. Netstrings http://cr.yp.to/proto/netstrings.txt и BSON http://bsonspec.org/ приходите на ум.


выбор между POSIX shm_open/mmap интерфейс и более старая система V shmop это не будет иметь большого значения, потому что после системных вызовов инициализации вы получите ту же ситуацию: область памяти, которая разделяется между различными процессами. Если ваша система поддерживает его, я бы рекомендовал пойти с shm_open/mmap, потому что это более продуманный интерфейс.

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