Могу ли я передать объект другому процессу, просто передав его указатель в общую память? - PullRequest
7 голосов
/ 04 декабря 2010

У меня очень сложный класс (внутри него есть unordered_map и т. Д.), И я хочу поделиться им с ним в двух моих процессахМогу ли я просто передать указатель на него из одного процесса в другой?Я думаю, нет, но надеюсь услышать "Да!"Мне нужно иметь только один экземпляр этого объекта для всех процессов, потому что он очень большой, и все процессы будут работать только для чтения.

Ответы [ 6 ]

13 голосов
/ 04 декабря 2010

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

int descriptor = shm_open("/unique_name_here", O_RDWR | O_CREAT, 0777);

if (descriptor < 0) {
    /* handle error */
} else {

    ftruncate(descriptor, sizeof(Object));
    void *ptr = mmap(NULL, sizeof(Object), PROT_READ | PROT_WRITE | PROT_EXEC, MAP_SHARED, descriptor, 0);

    if (!ptr || ptr == MAP_FAILED)
        /* handle error */ ;

    Object *obj = new (ptr) Object(arguments);
}

водин процесс, а затем

int descriptor = shm_open("/the_same_name_here", O_RDWR | O_CREAT, 0777);

if (descriptor < 0) {
    /* handle error */
} else {

  Object *obj = (Object *) mmap(NULL, sizeof(Object), PROT_READ | PROT_WRITE | PROT_EXEC, MAP_SHARED, descriptor, 0);

  if (!obj || obj == MAP_FAILED)
      /* handle error */ ;
}

в другом.Есть еще много опций, и я не показывал код очистки, когда вы закончите, так что вы все равно должны прочитать man-страницы shm_open () и mmap (), но это должно помочь вам начать.Несколько вещей, которые нужно запомнить:

  • / Вся / память, которую использует объект, должна быть разделена.Например, если объект содержит указатели или ссылки на другие объекты, или динамически размещаемые члены (включая такие вещи, как контейнеры, std :: string и т. Д.), Вам придется использовать размещение new, чтобы создать все (или, по крайней мере, все, чтодолжен использоваться совместно с другими процессами) в блоке общей памяти.Вам не нужен новый shm_open () для каждого объекта, но вы должны отслеживать (в процессе создания) их размеры и смещения, которые могут быть подвержены ошибкам в нетривиальных случаях и абсолютно бесполезны, если у вас естьпричудливые типы автоматического распределения, такие как контейнеры STL.

  • Если какой-либо процесс будет изменять объект после его совместного использования, вам потребуется отдельный механизм синхронизации.Это не хуже, чем то, что вы делаете в многопоточной программе, но вы должны подумать об этом.

  • Если процессам 'client' не нужно изменять общий объектВы должны открыть их дескрипторы с помощью O_RDONLY вместо O_RDWR и вызвать mmap () без флага разрешения PROT_WRITE.Если клиентские процессы могут вносить локальные изменения, которые не должны использоваться другими процессами, вызовите mmap () с MAP_PRIVATE вместо MAP_SHARED.Это значительно сократит объем необходимой синхронизации и риск ее испортить.

  • Если эти процессы будут выполняться в многопользовательской системе и / или общие данные могут быть конфиденциальными и /или это приложение высокой доступности, вам понадобится более сложное управление доступом, чем показано выше.Общая память является распространенным источником дыр в безопасности.

5 голосов
/ 04 декабря 2010

Нет, процесс не ( естественно ) разделяет память.Если опция Boost является опцией, вы можете посмотреть Boost.Interprocess для легкого совместного использования памяти.

4 голосов
/ 04 декабря 2010

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

0 голосов
/ 04 декабря 2010

Если вы используете Qt4, есть QSharedMemory или вы можете использовать сокеты и собственный протокол сериализации.

0 голосов
/ 04 декабря 2010

Если вы используете Linux, вы можете использовать общую память для хранения общих данных между процессами. Для общего случая взгляните на расширенную библиотеку IPC.

Но указатель из одного процесса нельзя использовать в другом (его адрес можно использовать при доступе к IO или некоторым специальным устройствам)

0 голосов
/ 04 декабря 2010

Хитрость в том, что память должна отображаться одинаково в обоих ваших процессах. Если ваша распределенная общая память может быть организована таким образом, она будет работать, но держу пари, что это будет очень сложно.

Есть несколько других возможностей. Первый - использовать массив; индексы массива будут работать в обоих процессах.

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

...