11.Linux网络编程-POSIX共享内存

一:POSIX共享内存
在Linux中,POSIX共享内存对象驻留在tmpfs伪文件系统中。系统默认挂载在/dev/shm目录下。当调用shm_open函数创建或打开POSIX共享内存对象时,系统会将创建/打开的共享内存文件放到/dev/shm目录下。

二:共享内存相关函数

#include <sys/mman.h>
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 <unistd.h>
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 <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/file.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <unistd.h>

#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 <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/file.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <unistd.h>

#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
发布了32 篇原创文章 · 获赞 3 · 访问量 1392

猜你喜欢

转载自blog.csdn.net/m0_37582216/article/details/105363824