如何在 C 语言中使用 Linux 的共享内存
- 2024-09-30 15:23:00
- admin 原创
- 86
问题描述:
我的一个项目出了点问题。
我一直在尝试寻找使用共享内存的有据可查的例子,fork()
但没有成功。
基本上,情况是当用户启动程序时,我需要在共享内存中存储两个值:current_path是一个char和一个file_name也是一个 char。
根据命令参数,启动一个新进程fork()
,该进程需要读取和修改存储在共享内存中的current_path变量,而file_name变量是只读的。
有没有关于共享内存的带有示例代码(如果可能的话)的好教程可以给我参考?
解决方案 1:
有两种方法:shmget
和mmap
。我将讨论,因为它更现代、更灵活,但如果您更喜欢使用旧式工具,mmap
您可以查看man shmget
(或本教程)。
该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_SHARED | MAP_ANONYMOUS;
// 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, -1, 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
", shmem);
memcpy(shmem, child_message, sizeof(child_message));
printf("Child wrote: %s
", shmem);
} else {
printf("Parent read: %s
", shmem);
sleep(1);
printf("After 1s, parent read: %s
", shmem);
}
}
解决方案 2:
以下是共享内存的一个例子:
#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]
");
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: */
if ((data = shmat(shmid, NULL, 0)) == (void *)-1) {
perror("shmat");
exit(1);
}
/* read or modify the segment, based on the command line: */
if (argc == 2) {
printf("writing to segment: \"%s\"
", argv[1]);
strncpy(data, argv[1], SHM_SIZE);
} else
printf("segment contains: \"%s\"
", data);
/* detach from the segment: */
if (shmdt(data) == -1) {
perror("shmdt");
exit(1);
}
return 0;
}
步骤:
使用 ftok 将路径名和项目标识符转换为 System V IPC 密钥
使用 shmget 分配共享内存段
使用 shmat 将 shmid 标识的共享内存段附加到调用进程的地址空间
对内存区域进行操作
使用 shmdt 分离
解决方案 3:
这些包括使用共享内存
#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);
解决方案 4:
试试这个代码示例,我测试过了,来源: 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
", shared_memory);
/* Determine the segment's size. */
shmctl (segment_id, IPC_STAT, &shmbuffer);
segment_size = shmbuffer.shm_segsz;
printf ("segment size: %d
", 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
", shared_memory);
/* Print out the string from shared memory. */
printf ("%s
", shared_memory);
/* Detach the shared memory segment. */
shmdt (shared_memory);
/* Deallocate the shared memory segment. */
shmctl (segment_id, IPC_RMID, 0);
return 0;
}
解决方案 5:
以下是 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;
}
解决方案 6:
我简化了@salezica 的答案,以便int
在父/子进程之间读/写共享。
还将包装函数重命名为shared_malloc
。
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <string.h>
#include <unistd.h>
void* shared_malloc(size_t size) {
int prot = PROT_READ | PROT_WRITE;
int flags = MAP_SHARED | MAP_ANONYMOUS;
return mmap(NULL, size, prot, flags, -1, 0);
}
int main() {
int* shared_x = (int *)shared_malloc(sizeof(int));
* shared_x = 3;
int pid = fork();
if (pid == 0) {
printf("Child read: %d
", *shared_x);
* shared_x = 4;
printf("Child wrote: %d
", *shared_x);
} else {
printf("Parent read: %d
", *shared_x);
while(* shared_x == 3);
printf("After sync, parent read: %d
", *shared_x);
}
}
相关推荐
热门文章
项目管理软件有哪些?
- 2024年20款好用的项目管理软件推荐,项目管理提效的20个工具和技巧
- 2024年开源项目管理软件有哪些?推荐5款好用的项目管理工具
- 项目管理软件有哪些?推荐7款超好用的项目管理工具
- 项目管理软件哪个最好用?盘点推荐5款好用的项目管理工具
- 项目管理软件有哪些最好用?推荐6款好用的项目管理工具
- 项目管理软件有哪些,盘点推荐国内外超好用的7款项目管理工具
- 2024项目管理软件排行榜(10类常用的项目管理工具全推荐)
- 项目管理软件排行榜:2024年项目经理必备5款开源项目管理软件汇总
- 2024年常用的项目管理软件有哪些?推荐这10款国内外好用的项目管理工具
- 项目管理必备:盘点2024年13款好用的项目管理软件
热门标签
云禅道AD