一:POSIX共享内存
在Linux中,POSIX共享内存对象驻留在tmpfs伪文件系统中。系统默认挂载在/dev/shm目录下。当调用shm_open函数创建或打开POSIX共享内存对象时,系统会将创建/打开的共享内存文件放到/dev/shm目录下。
二:共享内存相关函数
#include
int shm_open(const char *name, int oflag, mode_t mode);
@shm_open:shm_open函数创建了共享内存区域,此时会在/dev/shm/创建共享内存文件;
@int :成功返回非负整数文件描述符;失败返回-1
@name:共享内存对象的名字,必须以/打头,并且后续不能有其它/ ,形如/somename长度不能超过NAME_MAX(255)
@oflag:与open函数类似,可以是O_RDONLY、O_RDWR,还可以按位或上O_CREAT、O_EXCL、O_TRUNC等。
@mode:此参数总是需要设置,如果oflag没有指定了O_CREAT,可以指定为0
#include
int ftruncate(int fd, off_t length);
@ftruncate:修改共享内存对象大小,shm_open不像shmget一样可以设置共享内存的大小,但可以使用ftruncate 设置大小
@fd:成功返回0;失败返回-1
@length:长度
void *mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset);
@mmap:将共享内存对象映射到进程地址空间
@void *:成功返回映射到的内存区的起始地址;失败返回MAP_FAILED(-1)
@addr: 要映射的起始地址,设置为NULL时表示由系统决定映射区的起始地址
@len:映射到进程地址空间的字节数,长度单位是以字节为单位,不足一内存页按一内存页处理
@prot:期望的内存保护标志,不能与文件的打开模式冲突。是以下的某个值,可以通过或运算合理地组合在一起
PROT_EXEC 页内容可以被执行
PROT_READ 页内容可以被读取
PROT_WRITE 页可以被写入
PROT_NONE 页不可访问
@flags:指定映射对象的类型,映射选项和映射页是否可以共享。它的值可以是一个或者多个以下位的组合体
MAP_SHARED 与其它所有映射这个对象的进程共享映射空间。对共享区的写入,相当于输出到文件。 直到msync()或者munmap()被调用,文件实际上不会被更新。
MAP_PRIVATE 建立一个写入时拷贝的私有映射。内存区域的写入不会影响到原文件。这个标志和以 上标志是互斥的,只能使用其中一个。
MAP_LOCKED 锁定映射区的页面,从而防止页面被交换出内存。
@fd:文件描述符
@offset:被映射对象内容的起点
int munmap(void* start,size_t length);
@munmap:卸载共享内存
@int:失败返回-1,成功返回0
@start:共享内存地址
@length:共享内存大小
int shm_unlink(const char *name);
@int:成功返回0;失败返回-1
@shm_unlink:删除一个共享内存对象
@name: 共享内存对象的名字
三: 创建共享内存的基本步骤和实例
1)程序执行shm_open函数创建了共享内存区域,此时会在/dev/shm/创建共享内存文件
2)通过ftruncate函数改变shm_open创建共享内存的大小为页大小sysconf(_SC_PAGE_SIZE)整数倍,如果不执ftruncate函数的话,会报Bus error的错误
3)通过mmap函数将创建的共享内存文件映射到内存
4)通过munmap卸载共享内存
5)通过shm_unlink删除内存共享文件
//编译:g++ -o shm_write shm_write.cpp -lrt
#include
#include
#include
#include
#include
#include
#include
#include
#define ERR_EXIT(m) do{ perror(m); exit(EXIT_FAILURE);}while(0);
typedef struct stu{
char name[32];
int age;
}STU;
int main (int argc, char *argv[])
{
int ret, i;
const char *memname = "/mymem";
size_t mem_size = sysconf(_SC_PAGE_SIZE);
int shmid = shm_open(memname, O_CREAT|O_TRUNC|O_RDWR, 0666);
if (shmid == -1)
ERR_EXIT("shm_open");
ret = ftruncate(shmid, mem_size);
if (ret != 0)
ERR_EXIT("ftruncate");
struct stat buf;
if (fstat(shmid, &buf))
ERR_EXIT("fstat");
printf("the shm object size is %ld\n", buf.st_size);
void* p = mmap(NULL, buf.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, shmid, 0);
if (p == MAP_FAILED)
ERR_EXIT("mmap");
STU* ptr = (STU*)p;
for (int i=0; i<10; i++, ptr++)
{
sprintf(ptr->name, "helloworld%d", i);
ptr->age = 20;
}
if (munmap(p, mem_size) != 0)
ERR_EXIT("munmap");
close(shmid);
return 0;
}
//g++ -o shm_read shm_read.cpp -lrt
#include
#include
#include
#include
#include
#include
#include
#include
#define ERR_EXIT(m) do{ perror(m); exit(EXIT_FAILURE);}while(0);
typedef struct stu{
char name[32];
int age;
}STU;
int main (int argc, char *argv[])
{
int ret, i;
const char *memname = "/mymem";
size_t mem_size = sysconf(_SC_PAGE_SIZE);
int shmid = shm_open(memname, O_RDWR, 0666);
if (shmid == -1)
ERR_EXIT("shm_open");
ret = ftruncate(shmid, mem_size);
if (ret != 0)
ERR_EXIT("ftruncate");
struct stat buf;
if (fstat(shmid, &buf))
ERR_EXIT("fstat");
printf("the shm object size is %ld\n", buf.st_size);
void* p = mmap(NULL, buf.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, shmid, 0);
if (p == MAP_FAILED)
ERR_EXIT("mmap");
STU* ptr = (STU*)p;
for (int i=0; i<10; i++, ptr++)
{
printf("%s:%d\n", ptr->name, ptr->age);
}
if (munmap(p, mem_size) != 0)
ERR_EXIT("munmap");
if (shm_unlink(memname) != 0)
ERR_EXIT("shm_unlink");
close(shmid);
return 0;
}
结果:
root@ubuntu:/home/share/eclipse_workspace/demo# ./shm_write
the shm object size is 4096
root@ubuntu:/home/share/eclipse_workspace/demo# cat /dev/shm/mymem
helloworld0helloworld1helloworld2helloworld3helloworld4helloworld5helloworld6helloworld7helloworld8helloworld9root@ubuntu:/home/share/eclipse_workspace/demo#
root@ubuntu:/home/share/eclipse_workspace/demo#
root@ubuntu:/home/share/eclipse_workspace/demo#
root@ubuntu:/home/share/eclipse_workspace/demo# ./shm_read
the shm object size is 4096
helloworld0:20
helloworld1:20
helloworld2:20
helloworld3:20
helloworld4:20
helloworld5:20
helloworld6:20
helloworld7:20
helloworld8:20
helloworld9:20