cpp跨平台共享内存进程通讯

2024/04/04

Tags: C++ SharedMemory IPC

Table of Contents

1. Linux的两种共享内存机制,及选用

shmgetshm_open 是两种不同的共享内存机制,它们在使用方式和本质上有所不同。

1.1 System V 共享内存

1.2 映射文件共享内存

由于要考虑跨平台封装,windows上共享内存映射也是文件系统相关,所以选择映射文件的这个套机制

2. 查看共享内存分配情况

2.1 POSIX - System V

虽然我们选用了映射文件共享内存的方式,但是还是简单提一下system v共享内存机制查看已分配内存的方式

1
2
3
4
5
6
7
8
9
huangbinbin@cs-bj:~$ ipcs -m

------ Shared Memory Segments --------
key        shmid      owner      perms      bytes      nattch     status
0x00000000 557056     chenyan    600        524288     2          dest
0x00000000 557057     chenyan    600        2097152    2          dest
0x00000000 491523     hanhaopeng 600        8388608    2          dest
0x00000000 1146884    huangbinbi 600        67108864   2          dest
...

2.2 POSIX - 映射文件共享内存

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
[huangbinbin@dv-srv01 ~]$ ll /dev/shm/
total 10924
-rwx------ 1 renyanan  algr 65536 Mar 12 16:27 3289461crawl10r0
-rwx------ 1 renyanan  algr 65536 Mar 12 16:27 3289461crawl10s0
-rwx------ 1 renyanan  algr 65536 Mar 12 16:30 3289461crawl11r0
-rwx------ 1 renyanan  algr 65536 Mar 12 16:30 3289461crawl11s0
-rwx------ 1 renyanan  algr 65536 Mar 12 16:31 3289461crawl12r0
-rwx------ 1 renyanan  algr 65536 Mar 12 16:31 3289461crawl12s0
-rwx------ 1 renyanan  algr 65536 Mar 12 16:34 3289461crawl13r0
...

2.3 Windows

windows无法像linux那样列出所有系统中的共享内存文件,只能通用微软的运维工具process explorer查看section类型的句柄

image-20240402150152588

3. 封装代码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
#include <iostream>

#ifdef _WIN32 // Windows

#include <windows.h>

class SharedMemory {
public:
    SharedMemory(const char* name, size_t size):size(size) {
        handle = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, size, name);
        if (handle == NULL) {
            std::cerr << "Failed to create shared memory" << std::endl;
        }
    }

    ~SharedMemory() {
        CloseHandle(handle);
    }

    void* map() {
        return MapViewOfFile(handle, FILE_MAP_ALL_ACCESS, 0, 0, 0);
    }

    void unmap(void* addr) {
        UnmapViewOfFile(addr);
    }

private:
    HANDLE handle;
};

#else // Linux and macOS

#include <fcntl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <unistd.h>

class SharedMemory {
public:
    SharedMemory(const char* name, size_t size):size(size) {
        fd = shm_open(name, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
        if (fd == -1) {
            std::cerr << "Failed to create shared memory" << std::endl;
        }
        ftruncate(fd, size);
    }

    ~SharedMemory() {
        close(fd);
        // Unlink shared memory object
        // shm_unlink(name); // Uncomment this if you want to remove shared memory object after use
    }

    void* map() {
        return mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    }

    void unmap(void* addr) {
        munmap(addr, size);
    }

private:
    int fd;
    size_t size;
};

#endif

使用示例,

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
int main() {
    SharedMemory shm("MySharedMemory", 1024);
    void* addr = shm.map();
    if (addr == MAP_FAILED) {
        std::cerr << "Failed to map shared memory" << std::endl;
        return 1;
    }

    // do stuff

    shm.unmap(addr);

    return 0;
}

4. 注意事项

4.1 链接库

linux下需要链接rt库

1
$ g++ -o main main.cpp -lrt

4.2 权限问题

linux上 ,执行sub_open的进程如果是root,那么要打开这个共享内存文件,也需要是以root启动的进程

否则 map返回的addr可能会是 MAP_FAILED ,注意,map失败不是返回nullptr,是MAP_FAILED 也就是 (void*)-1

参考

ChatGPT (openai.com)

Creating Named Shared Memory - Win32 apps | Microsoft Learn

>> Home

Comments