C++共享内存实现(windows和linux)

版权声明:原创文章如需转载,请在左侧博主描述栏目扫码联系我并取得授权,谢谢 https://blog.csdn.net/u012234115/article/details/82114631

共享内存是一种进程间通信的方式,速度比较快

基本原理:以页面为单位,将一个普通文件映射到内存中,达到共享内存和节约内存的目的,通常在需要对文件进行频繁读写时使用,这样用内存读写取代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相关函数,这种方式读写速度更快,但是文件不落地,共享内存大小受限

猜你喜欢

转载自blog.csdn.net/u012234115/article/details/82114631
今日推荐