共享内存是一种进程间通信的方式,速度比较快
基本原理:以页面为单位,将一个普通文件映射到内存中,达到共享内存和节约内存的目的,通常在需要对文件进行频繁读写时使用,这样用内存读写取代I/O读写,以获得较高的性能
windows和linux都提供了原生的系统级的C++接口,可以将文件映射到内存
windows中使用CreateFileMapping
linux使用mmap
代码示例
这里实现了两个进程,writer进程往共享内存里写数据,reader进程从共享内存里读数据
main_writer.cpp
#include <iostream>
#include <string>
#include <thread>
#include <chrono>
#ifdef _WIN32
#include <windows.h>
#elif __linux
#include <string.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#endif
using namespace std;
#ifdef _WIN32
struct MyData
{
string name;
int age;
MyData(string _name, int _age) : name(_name), age(_age)
{}
};
void writeMemory()
{
// define shared data
char *shared_file_name = "my_shared_memory";
unsigned long buff_size = 4096;
char share_buffer[] = "greetings, hello world";
//MyData share_buffer("Tom", 18);
// create shared memory file
HANDLE dump_file_descriptor = CreateFile(shared_file_name,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_ALWAYS, // open exist or create new, overwrite file
FILE_ATTRIBUTE_NORMAL,
NULL);
if (dump_file_descriptor == INVALID_HANDLE_VALUE)
cout << "create file error" << endl;
HANDLE shared_file_handler = CreateFileMapping(
dump_file_descriptor, // Use paging file - shared memory
NULL, // Default security attributes
PAGE_READWRITE, // Allow read and write access
0, // High-order DWORD of file mapping max size
buff_size, // Low-order DWORD of file mapping max size
shared_file_name); // Name of the file mapping object
if (shared_file_handler)
{
// map memory file view, get pointer to the shared memory
LPVOID lp_base = MapViewOfFile(
shared_file_handler, // Handle of the map object
FILE_MAP_ALL_ACCESS, // Read and write access
0, // High-order DWORD of the file offset
0, // Low-order DWORD of the file offset
buff_size); // The number of bytes to map to view
// copy data to shared memory
memcpy(lp_base, &share_buffer, sizeof(share_buffer));
FlushViewOfFile(lp_base, buff_size); // can choose save to file or not
// process wait here for other task to read data
cout << "already write to shared memory, wait ..." << endl;
//cout << share_buffer << endl;
this_thread::sleep_for(chrono::seconds(10));
// close shared memory file
UnmapViewOfFile(lp_base);
CloseHandle(shared_file_handler);
CloseHandle(dump_file_descriptor);
//unlink(shared_file_name);
cout << "shared memory closed" << endl;
}
else
cout << "create mapping file error" << endl;
}
#elif __linux
struct MyData
{
char name[20];
int age;
};
void writeMemory()
{
// specify shared file path
char *shared_file_name = "/home/user/codetest/my_shared_memory";
// define shared data
// unsigned long buff_size = 4096;
// char share_buffer[] = "greetings, hello world";
// MyData share_buffer("Tom", 18);
MyData share_buffer = { "Tom", 18 };
// create mmap file
int fd = open(shared_file_name, O_CREAT | O_RDWR | O_TRUNC, 00777);
if (fd < 0)
cout << "create file error" << endl;
size_t write_size = sizeof(share_buffer);
ftruncate(fd, write_size); // extend file size
// map memory to file
void *p = mmap(NULL, write_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
// copy data to shared memory
memcpy(p, &share_buffer, write_size);
cout << "already write to shared memory, wait ..." << endl;
//cout << share_buffer << endl;
this_thread::sleep_for(chrono::seconds(10));
// unmap and close
munmap(p, write_size);
close(fd);
}
#endif
int main()
{
writeMemory();
return 0;
}
main_reader.cpp
#include <iostream>
#include <string>
#ifdef _WIN32
#include <windows.h>
#elif __linux
#include <string.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#endif
using namespace std;
#ifdef _WIN32
struct MyData
{
string name;
int age;
MyData(string _name, int _age) : name(_name), age(_age)
{}
};
void readMemory()
{
char *shared_file_name = "my_shared_memory";
// open shared memory file
HANDLE shared_file_handler = OpenFileMapping(
FILE_MAP_ALL_ACCESS,
NULL,
shared_file_name);
if (shared_file_handler)
{
LPVOID lp_base = MapViewOfFile(
shared_file_handler,
FILE_MAP_ALL_ACCESS,
0,
0,
0);
// copy shared data from memory
cout << "read shared data: " << endl;
const unsigned long buff_size = 4096;
//char share_buffer[buff_size] = { 0 };
//strcpy(share_buffer, (char *)lp_base);
char *share_buffer = (char *)lp_base;
cout << share_buffer << endl;
/*MyData *my_data = (MyData *)lp_base;
cout << my_data->name << " " << my_data->age << endl;*/
// close share memory file
UnmapViewOfFile(lp_base);
CloseHandle(shared_file_handler);
}
else
cout << "open mapping file error" << endl;
}
#elif __linux
struct MyData
{
char name[20];
int age;
};
void readMemory()
{
// specify shared file path
char *shared_file_name = "/home/user/codetest/my_shared_memory";
// open mmap file
int fd = open(shared_file_name, O_RDONLY, 00777);
if (fd < 0)
cout << "open file error" << endl;
const unsigned long buff_size = 4096;
// size_t read_size = buff_size;
size_t read_size = sizeof(MyData);
// map file to memory
void *p = mmap(NULL, read_size, PROT_READ, MAP_SHARED, fd, 0);
cout << "read shared data: " << endl;
// char *share_buffer = (char *)p;
// cout << share_buffer << endl;
MyData *share_buffer = (MyData *)p;
cout << share_buffer->name << " " << share_buffer->age << endl;
// unmap and close
munmap(p, read_size);
close(fd);
}
#endif
int main()
{
readMemory();
getchar();
return 0;
}
注意:
内存映射其实是将内存内容保存到了一个本地文件上,读写进程都操作这个文件映射对内存空间
windows中必须两个进程都开启,写进程可以不将文件落地,读进程其实只是读内存,linux的写和读进程可以分离,必须将文件落地,指向同一个文件路径
可以传输复杂的结构体或者数组类型,需要计算好buffer的size,其中linux貌似杜宇string类型支持不好,改用char数组
共享内存在实际使用中需要根据读写切换进行加锁保护
linux还有另外一种共享内存的方式,shm相关函数,这种方式读写速度更快,但是文件不落地,共享内存大小受限
---------------------
作者:踏莎行hyx
来源:优快云
原文:https://blog.youkuaiyun.com/u012234115/article/details/82114631
版权声明:本文为博主原创文章,转载请附上博文链接!