共享内存

Posted 一字千金

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了共享内存相关的知识,希望对你有一定的参考价值。

共享内存

目录

1       共享内存的作用... 1

2       共享内存的实现方式... 1

2.1      Window服务端实现方式... 1

2.2      Windows客户端读取共享内存流程... 3

2.3      Linux服务端写入数据到共享内存... 4

2.4      Linux客户端读数据流程... 6

3       共享内存的实例代码... 8

 

1         共享内存的作用

共享内存属于内核级的操作,所以共享内存的名称不能与信号量、槽等相同。共享内存是用一个名称来标记一块内存,所有的进程都可以通过名称去访问这块内存,实现进程间的数据通讯,所以共享内存的名称一定要是全局唯一的。

2         共享内存的实现方式

写入数据到共享内存的称为服务端,从共享内存读取数据的称为客户端。Window或linux下实现方式是服务端通过名称创建共享内存,然后将数据写入到共享内存。客户端也采用相同的名称打开共享内存,读取其中的数据。进而实现进程间通讯。

2.1  Window服务端实现方式

(1)服务端创建共享内存

HANDLE CreateFileMapping(

HANDLE hFile, //物理文件句柄,

LPSECURITY_ATTRIBUTES lpAttributes, //安全设置

DWORD flProtect, //保护设置

DWORD dwMaximumSizeHigh, //高位文件大小

DWORD dwMaximumSizeLow, //低位文件大小

LPCTSTR lpName //共享内存名称

);

1) 物理文件句柄

 

这个参数可以传入0xFFFFFFFF(INVALID_HANDLE_VALUE),表示直接在内存中开辟一块地址,这是需要设置需要申请的内存空间的大小。如果传入一个CreateFile函数 返回的文件句柄,表示用这个文件作为保存数据的载体。这样 CreateFileMapping 就可以创建一个和物理文件大小无关的内存空间给你, 这时会返回给你的是一个和物理文件大小一样的内存空间地址范围。

2) 保护设置

就是安全设置, 不过一般设置NULL就可以了, 使用默认的安全配置。 在win2k下如果需要进行限制, 这是针对那些将内存文件映射共享给整个网络上面的应用进程使用时, 可以考虑进行限制。

3) 高位文件大小

 最大的文件大小。

4) 低位文件大小

 最小的内存空间大小,一般我们在共享内存的开头加一个结构体,表示共享内存的信息,这个最小空间设置为结构体的大小加上你需要的最小内存空间大小。

5)共享内存名称

用来标识共享内存的名称,需要全局唯一,而且与互斥量、槽等名称不能重复。

6) 返回值GetLastError的对应错误

ERROR_FILE_INVALID 如果企图创建一个零长度的文件映射, 应有此报

ERROR_INVALID_HANDLE 如果发现你的命名内存空间和现有的内存映射, 互斥量,信号量,临界区同名就麻烦了

ERROR_ALREADY_EXISTS 表示内存空间命名已经存在

 

(2)创建视图获取操作共享内存的地址

pView = MapViewOfFile(

        hMapFile,               // Handle of the map object

        FILE_MAP_ALL_ACCESS,    // Read and write access

        0,                      // High-order DWORD of the file offset

        VIEW_OFFSET,            // Low-order DWORD of the file offset

        VIEW_SIZE               // The number of bytes to map to view

        );

(3)用memcpy或者memove函数写入数据

memcpy_s(pview,1024,&player,dmessage);

(4)写完数据之后删除视图

UnmapViewOfFile(pView);

(5)关闭句柄,删除共享内存

CloseHandle(m_hFile);

2.2  Windows客户端读取共享内存流程

(1)   打开共享内存

HANDLE WINAPI OpenFileMapping(

  _In_ DWORD   dwDesiredAccess,//访问权限

  _In_ BOOL    bInheritHandle,//是否继承

  _In_ LPCTSTR lpName//共享内存的名称

);

(2)创建视图,获取操作共享内存的地址

pView = MapViewOfFile(

        hMapFile,               // Handle of the map object

        FILE_MAP_ALL_ACCESS,    // Read and write access

        0,                      // High-order DWORD of the file offset

        VIEW_OFFSET,            // Low-order DWORD of the file offset

        VIEW_SIZE               // The number of bytes to map to view

        );

(3)读取数据

(4)写完数据之后删除视图

UnmapViewOfFile(pView);

(5)关闭句柄,删除共享内存

CloseHandle(m_hFile);

2.3  Linux服务端写入数据到共享内存

(1)服务端创建共享内存

所需头文件:

#include <sys/ipc.h>

#include <sys/shm.h>

int shmget(key_t key, size_t size,int shmflg);

功能:创建或打开一块共享内存区。

参数:

key:进程间通信键值,ftok() 的返回值。

size:该共享存储段的长度(字节)。

shmflg:标识函数的行为及共享内存的权限,其取值如下:

IPC_CREAT:如果不存在就创建

IPC_EXCL:  如果已经存在则返回失败

位或权限位:共享内存位或权限位后可以设置共享内存的访问权限,格式和 open() 函数的 mode_t。

返回值:

成功:共享内存标识符。

失败:-1。

(2)创建视图,获取操作共享内存的地址

#include <sys/types.h>

#include <sys/shm.h>

void *shmat(int shmid, const void *shmaddr, int shmflg);

功能:

将一个共享内存段映射到调用进程的数据段中。简单来理解,让进程和共享内存建立一种联系,让进程某个指针指向此共享内存。

参数:

shmid:共享内存标识符,shmget() 的返回值。

shmaddr:共享内存映射地址(若为 NULL 则由系统自动指定),推荐使用 NULL。

shmflg:共享内存段的访问权限和映射条件( 通常为 0 ),具体取值如下:

 

 

 

0:共享内存具有可读可写权限。

SHM_RDONLY:只读。

SHM_RND:(shmaddr 非空时才有效)

返回值:

成功:共享内存段映射地址( 相当于这个指针就指向此共享内存 )

 失败:-1

(3)写入数据

(4)解除共享内存映射

所需头文件:

#include <sys/types.h>

 #include <sys/shm.h>

int shmdt(const void *shmaddr);

功能:

将共享内存和当前进程分离( 仅仅是断开联系并不删除共享内存,相当于让之前的指向此共享内存的指针,不再指向)。

参数:

shmaddr:共享内存映射地址。

返回值:成功:0失败:-1

(5)删除共享内存

#include <sys/ipc.h>

#include <sys/shm.h>

int shmctl(int shmid, int cmd, struct shmid_ds *buf);

功能:

共享内存属性的控制。

参数:

shmid:共享内存标识符。

cmd:函数功能的控制,其取值如下:

IPC_RMID:删除。(常用 )
IPC_SET:设置 shmid_ds 参数,相当于把共享内存原来的属性值替换为 buf 里的属性值。
IPC_STAT:保存 shmid_ds 参数,把共享内存原来的属性值备份到 buf 里。
SHM_LOCK:锁定共享内存段( 超级用户 )。
SHM_UNLOCK:解锁共享内存段。

 

SHM_LOCK 用于锁定内存,禁止内存交换。并不代表共享内存被锁定后禁止其它进程访问。其真正的意义是:被锁定的内存不允许被交换到虚拟内存中。这样做的优势在于让共享内存一直处于内存中,从而提高程序性能。

 

buf:shmid_ds 数据类型的地址(具体类型请点此链接 ),用来存放或修改共享内存的属性。

返回值:成功:0失败:-1

 

2.4  Linux客户端读数据流程

#include <stdio.h>

#include <stdlib.h>

#include <sys/shm.h>

#include <sys/ipc.h>

#include <sys/types.h>

#include <unistd.h>

#include <string.h>

#include <errno.h>

 

#define BUF_SIZE 4096

 

int main()

{

    void *shm_addr = NULL;

 

    int shmid;

    // 使用约定的键值打开共享内存

    shmid = shmget((key_t) 1234, BUF_SIZE, IPC_CREAT);

    printf("shmid : %u\n", shmid);

    if (shmid == -1)

    {

        perror("shmget error!");

        exit(1);

    }

 

    // 将共享内存附加到本进程

    shm_addr = shmat(shmid, NULL, 0);

    if (shm_addr == (void *) -1)

    {

        perror("shmat error!");

        exit(1);

    }

 

    // 读取数据

    char tmp[BUF_SIZE];

    bzero(tmp, BUF_SIZE);

    memcpy(tmp, shm_addr, BUF_SIZE);

    printf("read from shared memory: %s\n", tmp);

 

    sleep(5);

 

    // 分离

    if (shmdt(shm_addr) == -1)

    {

        printf("shmdt error!\n");

        exit(1);

    }

 

    // 删除共享内存

    if (shmctl(shmid, IPC_RMID, 0) == -1)

    {

        printf("shmctl error!\n");

        exit(1);

    }

}

3         共享内存的实例代码

基于内存的共享内存

https://blog.csdn.net/taily_duan/article/details/51692999

基于文件的共享内存封装类详细

https://blog.csdn.net/hzqhbc/article/details/24408399

https://blog.csdn.net/zsc_976529378/article/details/52604973

 

linux共享内存实例

https://blog.csdn.net/xiejingfa/article/details/50888870

 

以上是关于共享内存的主要内容,如果未能解决你的问题,请参考以下文章

进程间通信(共享内存)

如何设置linux的共享内存

linux共享内存的控制释放

共享内存实现原理

gpu共享内存几乎不被使用,共享gpu内存用不了

共享内存