Управление общей памятью Unix - PullRequest
3 голосов
/ 01 апреля 2012

Мы знаем, что общая память в Windows реализуется через файлы с отображенной памятью, поддерживаемые системным файлом подкачки, и она всегда управляется подсчетом ссылок (http://msdn.microsoft.com/en-us/library/windows/desktop/aa366537(v=vs.85).aspx).

Интересно, Unix делает это аналогичным образом? Кто-то (http://stackoverflow.com/q/4278391/939142) говорит, что Unix также управляет shm с подсчетом ссылок. Я попробовал эксперимент на Mac OS X и обнаружил, что это не так.

Используя код, приведенный в конце, скомпилируйте две программы: хост и клиент. Тип

./host 

, который создает shm, записывает (int) 10 по первому адресу и завершает работу. Затем введите

./client <shmid>

для проверки сегмента shm, который присоединяется к созданному shm, печатает первый int и выходит.

Обратите внимание, что мы использовали shmat и shmdt для подключения / отключения от shm, и shmget для создания shm.

Чтобы уничтожить shm, мы должны сделать это вручную, используя shmctl.

Вывод: shm не управляется как подсчет ссылок в Unix, по крайней мере для Mac OS X

/************************** host.c ****************************/

#include <stdio.h>
#include <sys/shm.h>
#include <mach/vm_param.h>
#include <assert.h>

int
main(int argc, char** argv)
{
int value = 10;
int id;
void* ptr;
    /* create a new shm */
id = shmget(IPC_PRIVATE, PAGE_SIZE, IPC_CREAT | 0666);
assert(id != -1);
    /* attach to the new shm */
ptr = shmat(id, (const void*) NULL, 0);
assert((int*) ptr != -1);
    /* print the id so that client can use */
printf("shm id = %ld\n", id);
printf("address of id = %ld, length = %ld\n", ptr, PAGE_SIZE);
((int*) ptr)[0] = value;
printf("value at address %ld = %ld\n", ptr, *(int*) ptr);
/* detach from the shm and exit */
    shmdt((const void*) ptr);
return 0;
}


/************************** host.c ****************************/

#include <stdio.h>
#include <stdlib.h>
#include <sys/shm.h>
#include "assert.h"
#include <mach/vm_param.h>

int
main(int argc, char** argv)
{
void* ptr;
int id = atoi(argv[1]);
assert(id != -1);
    /* attach to the shm */
ptr = shmat(id, NULL, 0);
assert(ptr != -1);
printf("value at ptr = %ld = %ld\n", ptr, *(int*) ptr);
shmdt((const void*) ptr);
return 0;
}

1 Ответ

2 голосов
/ 01 апреля 2012

Это не чистый подсчет ссылок.Согласно shmctl (2):

IPC_RMID : отметить сегмент, подлежащий уничтожению.Сегмент будет фактически уничтожен только после того, как последний процесс отсоединит его (т. Е. Когда элемент shm_nattch связанной структуры shmid_ds равен нулю).Вызывающий должен быть владельцем или создателем,

Это означает, что IPC_RMID не удалит сразу, а только после того, как количество ссылок уменьшится до нуля в следующий раз.

Это позволяет вамдля достижения нескольких целей с помощью одного и того же инструмента:

  • Либо подход сервер / клиент, при котором сервер создает, подключает и сразу устанавливает RMID.Тогда клиенты могут подключаться, пока сервер находится здесь.Если сервер выходит из строя, клиенты должны отключиться, а ресурс очищается ОС.

  • Или подход «сообщение»: кто-то пишет сообщение, прикрепляет его в известном месте,После этого может прийти кто-то другой, найдите сообщение и действуйте соответственно.Это то, что вы сделали.Этот подход, конечно, более открыт для мусора ресурсов.Но для этого есть варианты.

...