c - 对 mmap() 返回感到困惑 - 两个不同的指针?
问题描述
目前试图了解内存映射在 Linux 中是如何工作的(或者一般来说,真的),我正在关注操作系统概念中 POSIX 系统中的共享内存的一个示例。这两个文件如下:
生产者档案
// This is the producer file for the Shared memory object
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <errno.h>
#include <sys/mman.h>
int main()
{
// ---------------- PRODUCER ESTABLISHES SHARED MEMORY OBJECT AND WRITES TO IT ----------------
// Specifying the size in bytes of the shared memory object
const int SIZE = 4096;
// Name of the shared memory space
const char *name = "OS";
// The actual strings to write to shared memory
const char *message_0 = "Hello";
const char *message_1 = "World!";
// Shared memory file descriptor will be stored in this
int fd;
// Pointer to the shared memory object will be stored in this
char *ptr;
// Checking error
int errnum;
// Create a shared memory object. This opens (establishes a connection to) a shared memory object.
fd = shm_open(name, O_CREAT | O_RDWR,0666);
if (fd == -1)
{
errnum = errno;
fprintf(stdout, "Value of errno: %d\n", errno);
perror("Error printed by perror");
fprintf(stdout, "Error opening file: %s\n", strerror(errnum));
return 1;
}
// Configure the size of the shared-memory object to be 4096 bytes
ftruncate(fd, SIZE);
// Memory map the shared memory object
ptr = (char *) mmap(0, SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
printf("Ptr is: %p\n", ptr);
if (ptr == MAP_FAILED)
{
errnum = errno;
fprintf(stdout, "Value of errno in ptr: %d\n", errno);
perror("Error printed by perror");
fprintf(stdout, "Error opening file: %s\n", strerror(errnum));
return 1;
}
// Write to the shared memory object
sprintf(ptr, "%s", message_0);
ptr += strlen(message_0);
sprintf(ptr, "%s", message_1);
ptr += strlen(message_1);
return 0;
}
消费者档案
// This is the consumer file for the Shared memory object, in which it reads what is in the memory object OS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <errno.h>
#include <sys/mman.h>
int main()
{
// Size in bytes of shared memory object
const int SIZE = 4096;
// Name of the shared memory space
const char *name = "OS";
// Shared memory file descriptor will be stored in this
int fd;
// Pointer to the shared memory object will be stored in this
char *ptr;
// Checking error
int errnum;
// Open the shared memory object
fd = shm_open(name, O_RDWR, 0666);
// If error in shm_open()
if (fd == -1)
{
errnum = errno;
fprintf(stdout, "Value of errno: %d\n", errno);
perror("Error printed by perror");
fprintf(stdout, "Error opening file: %s\n", strerror(errnum));
return 1;
}
// Memory-map the shared memory object
ptr = (char *) mmap(0, SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
printf("Ptr is: %p\n", ptr);
if (ptr == MAP_FAILED)
{
errnum = errno;
fprintf(stdout, "Value of errno in ptr: %d\n", errno);
perror("Error printed by perror");
fprintf(stdout, "Error opening file: %s\n", strerror(errnum));
return 1;
}
// Read from the shared memory object
printf("%s\n", (char *) ptr);
// Remove the shared memory object (delete it)
shm_unlink(name);
return 0;
}
当我打印指向共享内存对象 ( printf("Ptr value: %p\n, ptr)
) 的指针时,我得到了消费者和生产者文件的两个不同值。为什么会这样?
据我了解,指针ptr
指向物理内存中的共享内存对象。通过将其映射到它们的地址空间,该物理内存仅在两个进程之间共享。但是,这将要求指针指向物理内存中的相同地址,不是吗?还是指向虚拟内存(即进程的地址空间)?如果是这样,它本身是否指向物理内存?
谢谢!
解决方案
每个进程都有自己的虚拟内存地址空间。通常,每个进程从虚拟内存到物理内存的映射是不同的。虽然共享内存可能位于地址 0x1000 的物理内存中,但生产者进程可能会将其映射到地址 0x7000 的虚拟内存中,而消费者进程可能会将其映射到地址 0x4000 的虚拟内存中。
此外,如果共享内存由于某种原因被换出内存,系统可以稍后将其重新加载到不同的物理地址,例如 0x13000,并更新进程中的映射,使其在每个进程中出现在与之前相同的地址生产者和消费者过程。
推荐阅读
- jquery-ui - jQuery可拖动 - 从拖动事件返回取消后重新激活
- visual-studio-code - 在 VSCode 中每次保存时运行 rsync
- php - 为什么没有加载 xdebug 3?
- sql - SQL Join 三张表;表 1 中的返回值,其中表 2 中的所有实例都具有相同的字段值
- spring-security - spring security 编码密码看起来不像 BCrypt
- android - Android 音频均衡器
- mongodb - Mongodb:除非完全升级到 featureCompatibilityVersion 3.6,否则无法传递逻辑会话 ID
- postgresql - Scala:缺少隐式泛型参数 shapeless.LabelledGeneric.Aux[T,L],如何提供?
- sql - 使用元数据表创建自动通用脚本以插入具有相同结构的另一个表
- macos - 适用于 VMware Fusion 12 的 bios.440.rom 文件