如何在Linux中使用共享内存
我的一个项目有点问题。
我一直在试图find一个使用fork()
共享内存但是没有成功的例子。
基本上情况是,当用户启动程序时,我需要在共享内存中存储两个值: current_path是char * , file_name也是char * 。
根据命令参数的不同,使用fork()
启动新进程,并且该进程需要读取和修改存储在共享内存中的current_pathvariables,而file_namevariables是只读的。
有没有一个很好的教程共享内存与示例代码(如果可能),你可以指示我?
谢谢,bleepzter
有两种方法: shmget
和mmap
。 我将讨论mmap
,因为它更现代和更灵活,但是如果你愿意使用旧式的工具,你可以看看man shmget
( 或本教程 )。
可以使用mmap()
函数来分配具有高度可定制参数的内存缓冲区,以控制访问和权限,并在必要时使用文件系统存储来备份它们。
以下函数创build一个进程可以与其subprocess共享的内存缓冲区:
#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); }
以下是使用上面定义的函数分配缓冲区的示例程序。 父进程将写入一个消息fork,然后等待其subprocess修改缓冲区。 这两个进程都可以读写共享内存。
#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将path名和项目标识符转换为System V IPC密钥
2-使用分配共享内存段的shmget
3-使用shmat将由shmid标识的共享内存段连接到调用进程的地址空间
4-在内存区域进行操作
5-使用shmdt分离
“高级Linux编程”一书的第5章很好地介绍了Linux与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 '\0' 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; }
试试这个代码示例,我testing了它,来源: 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; }