Как использовать общую память с Linux в C
у меня есть небольшая проблема с одним из моих проектов.
Я пытаюсь найти хорошо документированный пример использования общей памяти с fork()
но безуспешно.
в основном в том, что когда пользователь запускает программу, мне нужно хранить два значения в общей памяти: current_path что это char* и имя_файла, который также char*.
в зависимости от команды аргументы, новый процесс запускается с fork()
и этот процесс должен прочитать и изменить current_path переменной, хранящейся в общей памяти, в то время как имя_файла переменная доступна только для чтения.
есть ли хороший учебник по общей памяти с примером кода (если это возможно), что вы можете направить меня?
спасибо, бипзтер
6 ответов:
есть два подхода:
shmget
иmmap
. Я буду говорить оmmap
, так как он более современный и гибкий, но вы можете взглянуть наman shmget
(или в этом уроке) если вы предпочитаете использовать инструменты старого стиля.The
mmap()
функция может использоваться для выделения буферов памяти с настраиваемыми параметрами для управления доступом и разрешениями, а также для их резервного копирования с помощью хранилища файловой системы, если это необходимо.следующая функция создает буфер в памяти, которым процесс может поделиться со своими дочерними элементами:
#include <stdio.h> #include <stdlib.h> #include <sys/mman.h> void* create_shared_memory(size_t size) { // Our memory buffer will be readable and writable: int protection = PROT_READ | PROT_WRITE; // The buffer will be shared (meaning other processes can access it), but // anonymous (meaning third-party processes cannot obtain an address for it), // so only this process and its children will be able to use it: int visibility = MAP_ANONYMOUS | MAP_SHARED; // The remaining parameters to `mmap()` are not important for this use case, // but the manpage for `mmap` explains their purpose. return mmap(NULL, size, protection, visibility, 0, 0); }
ниже приведен пример программы, которая использует функцию, описанную выше, чтобы выделить буфер. Родительский процесс напишет сообщение, разветвит его и будет ждать, пока его дочерний процесс изменит буфер. Оба процесса могут читать и записывать общую память.
#include <string.h> #include <unistd.h> int main() { char* parent_message = "hello"; // parent process will write this message char* child_message = "goodbye"; // child process will then write this one void* shmem = create_shared_memory(128); memcpy(shmem, parent_message, sizeof(parent_message)); int pid = fork(); if (pid == 0) { printf("Child read: %s\n", shmem); memcpy(shmem, child_message, sizeof(child_message)); printf("Child wrote: %s\n", shmem); } else { printf("Parent read: %s\n", shmem); sleep(1); printf("After 1s, parent read: %s\n", shmem); } }
вот пример для общей памяти. Это может помочь :
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> #define SHM_SIZE 1024 /* make it a 1K shared memory segment */ int main(int argc, char *argv[]) { key_t key; int shmid; char *data; int mode; if (argc > 2) { fprintf(stderr, "usage: shmdemo [data_to_write]\n"); exit(1); } /* make the key: */ if ((key = ftok("hello.txt", 'R')) == -1) /*Here the file must exist */ { perror("ftok"); exit(1); } /* create the segment: */ if ((shmid = shmget(key, SHM_SIZE, 0644 | IPC_CREAT)) == -1) { perror("shmget"); exit(1); } /* attach to the segment to get a pointer to it: */ data = shmat(shmid, (void *)0, 0); if (data == (char *)(-1)) { perror("shmat"); exit(1); } /* read or modify the segment, based on the command line: */ if (argc == 2) { printf("writing to segment: \"%s\"\n", argv[1]); strncpy(data, argv[1], SHM_SIZE); } else printf("segment contains: \"%s\"\n", data); /* detach from the segment: */ if (shmdt(data) == -1) { perror("shmdt"); exit(1); } return 0; }
шагов : 1-Используйте ftok для преобразования пути и идентификатора проекта в Ключ IPC System V
2-Используйте shmget, который выделяет сегмент общей памяти
3-Используйте shmat для привязки сегмента общей памяти, идентифицированного shmid, к адресному пространству вызывающего процесса
4-выполните операции над областью памяти
5-отсоединить с помощью shmdt
Глава 5 из книги "Advanced Linux Programming" есть хорошее введение в IPC с Linux (вся книга в формате PDF)
Это включает в себя для использования общей памяти
#include<sys/ipc.h> #include<sys/shm.h> int shmid; int shmkey = 12222;//u can choose it as your choice int main() { //now your main starting shmid = shmget(shmkey,1024,IPC_CREAT); // 1024 = your preferred size for share memory // IPC_CREAT its a flag to create shared memory //now attach a memory to this share memory char *shmpointer = shmat(shmid,NULL); //do your work with the shared memory //read -write will be done with the *shmppointer //after your work is done deattach the pointer shmdt(&shmpointer, NULL);
вот пример mmap:
#include <sys/mman.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> /* * pvtmMmapAlloc - creates a memory mapped file area. * The return value is a page-aligned memory value, or NULL if there is a failure. * Here's the list of arguments: * @mmapFileName - the name of the memory mapped file * @size - the size of the memory mapped file (should be a multiple of the system page for best performance) * @create - determines whether or not the area should be created. */ void* pvtmMmapAlloc (char * mmapFileName, size_t size, char create) { void * retv = NULL; if (create) { mode_t origMask = umask(0); int mmapFd = open(mmapFileName, O_CREAT|O_RDWR, 00666); umask(origMask); if (mmapFd < 0) { perror("open mmapFd failed"); return NULL; } if ((ftruncate(mmapFd, size) == 0)) { int result = lseek(mmapFd, size - 1, SEEK_SET); if (result == -1) { perror("lseek mmapFd failed"); close(mmapFd); return NULL; } /* Something needs to be written at the end of the file to * have the file actually have the new size. * Just writing an empty string at the current file position will do. * Note: * - The current position in the file is at the end of the stretched * file due to the call to lseek(). * - The current position in the file is at the end of the stretched * file due to the call to lseek(). * - An empty string is actually a single '' character, so a zero-byte * will be written at the last byte of the file. */ result = write(mmapFd, "", 1); if (result != 1) { perror("write mmapFd failed"); close(mmapFd); return NULL; } retv = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, mmapFd, 0); if (retv == MAP_FAILED || retv == NULL) { perror("mmap"); close(mmapFd); return NULL; } } } else { int mmapFd = open(mmapFileName, O_RDWR, 00666); if (mmapFd < 0) { return NULL; } int result = lseek(mmapFd, 0, SEEK_END); if (result == -1) { perror("lseek mmapFd failed"); close(mmapFd); return NULL; } if (result == 0) { perror("The file has 0 bytes"); close(mmapFd); return NULL; } retv = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, mmapFd, 0); if (retv == MAP_FAILED || retv == NULL) { perror("mmap"); close(mmapFd); return NULL; } close(mmapFd); } return retv; }
попробуйте этот пример кода, я проверил его, источник:http://www.makelinux.net/alp/035
#include <stdio.h> #include <sys/shm.h> #include <sys/stat.h> int main () { int segment_id; char* shared_memory; struct shmid_ds shmbuffer; int segment_size; const int shared_segment_size = 0x6400; /* Allocate a shared memory segment. */ segment_id = shmget (IPC_PRIVATE, shared_segment_size, IPC_CREAT | IPC_EXCL | S_IRUSR | S_IWUSR); /* Attach the shared memory segment. */ shared_memory = (char*) shmat (segment_id, 0, 0); printf ("shared memory attached at address %p\n", shared_memory); /* Determine the segment's size. */ shmctl (segment_id, IPC_STAT, &shmbuffer); segment_size = shmbuffer.shm_segsz; printf ("segment size: %d\n", segment_size); /* Write a string to the shared memory segment. */ sprintf (shared_memory, "Hello, world."); /* Detach the shared memory segment. */ shmdt (shared_memory); /* Reattach the shared memory segment, at a different address. */ shared_memory = (char*) shmat (segment_id, (void*) 0x5000000, 0); printf ("shared memory reattached at address %p\n", shared_memory); /* Print out the string from shared memory. */ printf ("%s\n", shared_memory); /* Detach the shared memory segment. */ shmdt (shared_memory); /* Deallocate the shared memory segment. */ shmctl (segment_id, IPC_RMID, 0); return 0; }