C++ 为什么我可以使用POSIX创建一个大于/dev/shm上装载的大小的共享内存?
我试图在Ubuntu 16.04中使用共享内存IPC来处理错误。 首先,我使用df-h检查了/dev/shm中的可用内存,它有500米的可用空间,因此我快速编写了一些代码,以便检查如果我尝试创建一个大于装载大小的共享内存会发生什么。代码如下(已经修改了好几次,所以我知道这不是很整洁):C++ 为什么我可以使用POSIX创建一个大于/dev/shm上装载的大小的共享内存?,c++,c,posix,ipc,shared-memory,C++,C,Posix,Ipc,Shared Memory,我试图在Ubuntu 16.04中使用共享内存IPC来处理错误。 首先,我使用df-h检查了/dev/shm中的可用内存,它有500米的可用空间,因此我快速编写了一些代码,以便检查如果我尝试创建一个大于装载大小的共享内存会发生什么。代码如下(已经修改了好几次,所以我知道这不是很整洁): #包括 #包括 #包括 #包括 #包括 #包括 #包括 #包括 #包括 #包括 #包括 #包括 #包括 #包括 //静态常数尺寸=4000000L; 静态常数大小=701000000L; //静态常数大小=999
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
//静态常数尺寸=4000000L;
静态常数大小=701000000L;
//静态常数大小=9999999L;
外部内部错误;
静态整型打开(常量字符*名称、整型标签、模式)
{
int-shm=-1;
/*创建/打开共享内存区域*/
shm=shm_打开(名称、oflag、模式);
如果(shm==-1)
{/*打印错误*/
std::cout简短(且不令人满意的回答):如果/dev/shm
上没有足够的空间,您不能强制shm\u open
失败。(您可以使用setrlimit
来修改RLIMIT\u FSIZE
,通过显式设置进程文件大小限制来强制它失败,但这是一个全局设置,不适用于单个文件系统,因此几乎肯定不是您想要它做的。)
当Posix标准化共享内存时,考虑了各种实现选项,并尝试允许实现具有相当大的灵活性,只要它不使接口复杂化。特别是,许多Unix实现已经有了将文件对象直接映射到进程内存的机制,以及将内存映射到进程内存的机制ed文件系统,一种非常适合实现共享内存的组合:
简单共享内存显然是更通用的文件映射功能的特例。此外,文件映射接口的协议和实现相对广泛。在这些系统中,可以映射许多不同类型的对象(例如,文件、内存、设备等)使用相同的映射接口。这种方法既能最大限度地减少接口扩散,又能最大限度地提高使用映射接口的程序的通用性。(摘自)
特别是,“……上述要求并不妨碍[t]共享内存对象在实际文件系统上使用实际文件实现。”()。尽管我不相信Linux库会这样做,但Posix甚至允许将shm_open()
实现为包装普通open()的宏
call;对于只将共享内存映射到文件系统的实现(如Linux),不需要对系统接口进行特殊处理
突出显示ftruncate()
调用的一个方面很重要(添加了强调):
如果文件大小增加,扩展区域应显示为为零填充
许多文件系统都允许使用“稀疏文件”。在稀疏文件中,完全用零填充的文件块根本不会映射到物理存储上;如果应用程序读取其中一个块,它将收到一页零。如果一个块被修改并提交到磁盘,那么——也只有到那时——文件系统才会为该块分配存储。[注1]
零填充块的延迟分配意味着在ftruncate()
扩展文件的情况下,它只需要更新文件的元数据,使其能够快速返回。除非所需大小超过进程的文件大小限制(如果文件系统没有使用足够大的整数类型来表示文件大小,则为文件系统限制),ftruncate()
不会产生错误。如果无法分配物理存储(如果是内存映射文件,则为专用内存缓冲区),则会发生错误
这与Linux的乐观内存分配方法完全一致:mmap
总是成功的(只要地址空间可用),并且只有在实际使用内存时才会注意到错误。(但这种共享内存实现的特殊方法并不局限于使用乐观内存分配的方法。)
笔记
我曾经通过在软盘上存储2GB文件来证明这一点,但我想今天的许多读者甚至不知道软盘是什么,更不用说它的实际容量了
也许你定义的是一个最大的分配,这并不意味着所有的内存都将被分配到中间。当然,如果时间分配更多的内存比可用,错误将发生选择一种语言(显然是C++),并提出一个实际的。现在的代码在问题上是近似C++(而不是C)。,但似乎包含语法错误。在任何情况下,它似乎都比我所认为的要大得多,以演示问题。在write_shm()中,您似乎出现了一个一个接一个的错误<代码> >更改“代码”>大家好。我正在尝试使用C++,但是,作为共享的MEM LIBS授予我一个C接口,我使用这些函数调用。关于WreWestSHM错误:请让我们坚持到底。我仍然在试图弄清楚如何控制内存中的内存量,如果没有错误R,我可以分配/DEV/SHM。eportedNice回答,但正如你所说的,并不令人满意。因此,我可以祈祷不要要求比/de/shm上装载的数量更多的共享内存。我以为这会被考虑进去……非常感谢你的详细回答。@Fulgor3:我理解你的desazón,但你的不是唯一的用例。扩展shar并非小事在第一次创建内存段后,会重新创建内存段(所有用户都需要重做ftruncate和mmap,并且可能存在很多竞争条件),因此,如果他们持有可变长度的数据,通常只会使其“绝对足够大”(即太大)并依赖于ope
#include <iostream>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <cstring>
#include <stdint.h>
#include <stddef.h>
#include <cerrno>
//static const size_t size = 4000000L;
static const size_t size = 701000000L;
//static const size_t size = 999999999L;
extern int errno;
static int open(const char* name, int oflag, mode_t mode)
{
int shm = -1;
/* Create/Open a shared memory zone */
shm = shm_open(name, oflag, mode);
if(shm == -1)
{/* Print error */
std::cout << "!!!Error getting file descriptor while opening!!!" << std::endl;
std::cout << "ERROR:"<< strerror(errno) << std::endl;
}
return shm;
}
static void write_shm(void *addr, size_t size)
{
size_t i = 0;
uint32_t *shm_index = (uint32_t *)addr;
/* 4 bytes to be written in memory */
const char *test = "DEAD";
/* Maximum allowed memory address*/
ptrdiff_t max = (size+(ptrdiff_t)addr);
for (i = 0; (ptrdiff_t)(shm_index + i) < max; i++)
{
std:memcpy(&shm_index[i], (uint32_t*)test, sizeof(uint32_t));
}
}
static int adjust (int fd, size_t size)
{
std::cout<<__func__<<": The size of the shared memory is: "<<size<< std::endl;
int result = ftruncate(fd, size);
std::cout<<__func__<< "ftruncate return: " <<result<< std::endl;
errno = 0;
std::cout << "errno: "<< std::strerror(errno) <<std::endl;
if (result)
{/* Print error */;
std::cout << "FUNCION!!!Error in ftruncate!!!" << std::endl;
}
return result;
}
int main()
{
const char *name = "vardb";
int fd = -1;
int oflag = O_CREAT | O_EXCL | O_RDWR;
mode_t mode = S_IRWXU | S_IRWXG | S_IRWXO; // POSIX 1003.1 (Realtime Extensions)
size_t sizeToUse = (size/sizeof(uint32_t)* sizeof(uint32_t));
/* Let's try to get a file descriptor related to the shared memory*/
fd = open(name, oflag, mode);
if (fd == -1)
return fd;
/* Adjust the size of the shared memory to the expected one */
int result = adjust(fd, sizeToUse);
if (result)
return -1;
int prot = PROT_READ | PROT_WRITE;
int flags = MAP_SHARED;
/* Map the memory */
void *addr = mmap(NULL, size, prot, flags, fd, 0);
std::cout<<__func__<< "mmap return: " <<*(int *)addr<< std::endl;
std::cout<<__func__<< "mmap mapped to this address: " <<addr<< std::endl;
errno = 0;
std::cout << "mmap errno: "<< std::strerror(errno) <<std::endl;
struct stat fileStat;
if(fstat(fd, &fileStat) < 0)
return 1;
std::cout<<__func__<< "File Size: " <<fileStat.st_size<<" bytes"<<std::endl;
/* Write all the shared memory previously reserved for the test */
write_shm(addr, sizeToUse);
/* Release the memory */
munmap(addr, size);
return 0;
}