Как сохранить и извлечь структуру в общую область памяти в C - PullRequest
6 голосов
/ 24 ноября 2010

Для универсального назначения мне нужно создать круговой список до 10 имен файлов, а затем сохранить их в общей области памяти, чтобы 2 дочерних процесса могли читать / записывать в список (используя семафор для управления доступом).).Беда в том, что я новичок в C и чувствую потерю и отчаяние, потому что это полностью из моей глубины.Мне нужна помощь в «заполнении дыр» в моих знаниях.

Сейчас я просто фокусируюсь на этом по одной проблеме за раз, и в настоящее время я только пытаюсь включить свой круговой список вОбласть общей памяти.

Пока что у меня есть:

typedef struct FILE
{
   struct FILE *f_link;  /* forward link for linked list */
   char name[255];       /* name of the file */

} FILE_entry;

В качестве моей структуры, которая будет содержать ссылку на следующий файл (f_link).таким образом, я могу просто вызвать -> f_link, чтобы получить следующий элемент в списке, и где 10-й элемент будет просто иметь свою ссылку f_link обратно на 1-й.Моя причина для этого состоит в том, что я могу просто пройти по списку без итератора (и мне никогда не придется проверять конец списка, как это было бы с массивом).

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

Так что мой вопрос в 2 раза.Как сохранить свой связанный список в области общей памяти и как получить к нему доступ из области общей памяти?

Ответы [ 4 ]

9 голосов
/ 24 ноября 2010

shmget просто резервирует некоторое количество разделяемой памяти - например, создает файл фиксированного размера на диске.Флаги представляют собой маску разрешений (например, параметр mode для open) в младших 9 битах, плюс некоторые дополнительные флаги IPC_CREAT и IPC_EXCL, соответствующие O_CREAT и O_EXCL для open.Чтобы реально получить доступ к этой памяти, вам необходимо отобразить ее в адресное пространство вашего процесса («прикрепить» ее - аналогично mmap для файлов).Это делается с помощью shmat (который возвращает указатель).Затем вам нужно выделить ваши FILE структуры из этого указателя.Весь процесс выглядит примерно так:

int id;
FILE_entry *entries;

id = shmget(key, N * sizeof(FILE_entry), IPC_CREAT | 0644);
entries = (FILE_entry *) shmat(id, NULL, 0);

// you can now access entries as if it was a N-element array.
// to turn it into a circular list, link the entries appropriately.

После сопоставления вы можете работать с ним как с обычной памятью - поскольку является обычной памятью.В этом весь смысл!

РЕДАКТИРОВАТЬ : я забыл упомянуть одну важную оговорку.Помещение связанного списка в сегмент общей памяти, подобный этому, будет работать, только если все вовлеченные процессы отобразят его на один и тот же адрес!Так что вам нужно либо сделать это (используя второй аргумент shmat), либо переключаться с указателей на смещения относительно базового адреса диапазона разделяемой памяти.Это означает, что вы должны превратить ваше поле next из указателя в ptrdiff_t и добавить базовый адрес отображенного диапазона памяти всякий раз, когда вы загружаете его (и вычитать его, когда вы сохраняете его).

2 голосов
/ 24 ноября 2010

После того, как вы получите ключ от shmget, вы должны использовать его для получения фактического указателя через shmat.Вот пример:

int shmid;
key_t key;
FILE* shm;

shmid = shmget(key, sizeof(FILE) * 10, IPC_CREAT | 0666);
shm = shmat(shmid, NULL, 0);

Таким образом, вы сможете получить доступ к общей памяти, используя указатель shm.В этих ссылках вы можете видеть справочную страницу для shmget и shmat:

http://linux.die.net/man/2/shmget

http://linux.die.net/man/2/shmat

И см. http://www.cplusplus.com длядополнительная ссылка.Он также содержит ссылку на С.

Я не знаю, достаточно ли я ясен, поэтому дайте несколько комментариев, и я постараюсь разъяснить вам это, если это необходимо.

РЕДАКТИРОВАТЬ:На этом сайте вы можете найти очень простой пример: http://simplestcodings.blogspot.com/2010/08/ipc-shared-memory-implementation-in-c.html

2 голосов
/ 24 ноября 2010

Вы звоните shmat(identifier, NULL, 0), возвращая указатель на местоположение, на которое была отображена общая память в вашем процессе. Либо создайте свои объекты в этом месте, либо memcpy / memmove их в этом месте.

Возможно, вы найдете Руководство Beej по Unix IPC полезным, оно содержит раздел, посвященный общей памяти.

1 голос
/ 24 ноября 2010

Для флага необходимо указать как минимум IPC_CREATE, если вы хотите выделить новый сегмент совместно используемой памяти, в противном случае он будет выглядеть как запущенный существующий segemnt и завершится ошибкой, если не найдет его.

Во-вторых, поскольку сегмент совместно используемой памяти является непрерывным блоком памяти, вам необходимо иметь возможность хранить все 10 ваших структур FILE_entry вместе (или выделять 10 сегментов совместно используемой памяти - хм!).

Так что вам действительно нужно выделить достаточно памяти для массива, по крайней мере, из 10 структур FILE.

Наконец, FILE и FILE_entry - действительно плохие имена! Используйте что-то менее общее, например, MY_FILE_REF и MyFileRefEntry.

...