Windows和Linux下共享内存使用

源码地址: https://github.com/ylmbtm/GameProject3

      看过我开源代码的朋友知道,我这个项目在逻辑服和数据服进行数据同步采用的就是共享内存。其实数据同步的方式有很多种,其中使用较多的一种方式就是tcp网络协议同步,不过这种方式我觉得编码过程略嫌繁琐,使用也不够方便,开发效率不如共享内存。

      当然也有不少朋友吐槽共享内存,说共享内存没法跨机器分布式部署,说实话这个要看你的需求,只有根据项目需求制定的合适方案,以我工作这些年经验看,一般的手游项目远远够用了,共享内存除了开发方便还有几个优点,一是传输效率高,二是节约内存,三是服务器挂了之后能快速恢复。

      有好多的朋友不太了解,什么是共享内存,我这篇文章就来讲讲共享内存的一些基本知识和共享内存在windows和linux使用的一些异同点。

      共享内存是进程间同步数据的一种方式,它允许多个进程访问同一块物理内存,就是一段物理内存被同时映射到不同进程地址空间中,当一个进程修改这块内存的值,其它进程就可以直接读取到值的改变。

      对共享内存的操作实际上就五个关键操作:创建、打开、映射、释放、关闭或者删除, 这五个操作在windows和linux下是不一样的,我们先业看windows下的操作方法:

Windows版本:

1.创建共享内存

HANDLE CreateFileMapping(
    HANDLE hFile,
    LPSECURITY_ATTRIBUTES lpFileMappingAttributes,
    DWORD flProtect,
    DWORD dwMaximumSizeHigh,
    DWORD dwMaximumSizeLow,
    LPCWSTR lpName
    );

说明:

hFile: 这里是文件句柄,如果传实际的文件句柄就和linux 下的mmp文件映射类似的功能了,我们这里仅仅使用共享内存功能,赋值  INVALID_HANDLE_VALUE(0xFFFFFFFF)就可以了。

dwMaximumSizeLow: 创建的共享内存的大小。

lpName: 这个可以理解为这块共享内存的唯一标识,便于多个进程能访问到同一块共享内存。

2.打开共享内存

HANDLE OpenFileMapping(
    DWORD dwDesiredAccess,
    BOOL bInheritHandle,
    LPCWSTR lpName
    );

说明:

dwDesiredAccess: 需的访问权限,FILE_MAP_READ | FILE_MAP_WRITE表示同时需要读和写权限。

lpName:共享内存的唯一标识。

3.映射共享内存到进程空间

LPVOID MapViewOfFile(
    HANDLE hFileMappingObject,
    DWORD dwDesiredAccess,
    DWORD dwFileOffsetHigh,
    DWORD dwFileOffsetLow,
    SIZE_T dwNumberOfBytesToMap
    );

说明:

hFileMappingObject:共享内存句柄,就是上两个方法的返回值。

dwDesiredAccess:需的访问权限,FILE_MAP_READ | FILE_MAP_WRITE表示同时需要读和写权限。

返回值: 共享内存映射到本地进程的地址。

4.释放共享内存

BOOL UnmapViewOfFile(
    LPCVOID lpBaseAddress
);

说明:

lpBaseAddress:共享内存印射到本地进程的地址,也是上一个方法的返回值。

5.关闭共享内存

BOOL CloseHandle(
    HANDLE hObject
);

说明:

hObject:共享内存的句柄。

Linux:

1. 创建共享内存

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

key: 共享内存的key, 唯一标识这块共享内存。

size: 共享内存的大小 。

shmflg: 用于创建共享内存时可填值: 0666 | IPC_CREAT | IPC_EXCL

2. 打开共享内存

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

key: 共享内存的id, 唯一标识这块共享内存。

size: 共享内存的大小 ,用于打开共享内存时,可填0。

shmflg: 用于打开共享内存时,可填0。

3.映射共享内存到进程空间

void *shmat(int shm_id, const void *shm_addr, int shmflg);

shm_id:是由shmget()函数返回的共享内存标识。

shm_addr:指定共享内存连接到当前进程中的地址位置,通常为空,表示让系统来选择共享内存的地址。

shm_flg:是一组标志位,通常为0。

4.释放共享内存

int shmdt(const void *shmaddr);

shmaddr:是shmat()函数返回的地址指针,调用成功时返回0,失败时返回-1.

5.删除共享内存

int shmctl(int shm_id, int command, struct shmid_ds *buf);

shm_id:是由shmget()函数返回的共享内存标识。

command:命令 IPC_RMID表示删除共享内存, 但实际上并不是真的从内核删除一个段,而是仅仅把这个段标记为删除,实际的删除发生在这块共享内存nattch为0时。

在linux下还有命令用来管理共享内存

1.查看系统中的所有的共享内存

ipcs -m
------ Shared Memory Segments --------
key        shmid      owner      perms      bytes      nattch     status      
0x01010000 147226624  root       666        73728      2                       
0x01020000 147259393  root       666        1687552    2                       
0x01030000 147292162  root       666        114688     2                       
0x01040000 147324931  root       666        98304      2                       
0x01050000 147357700  root       666        73728      2                       
0x01060000 147390469  root       666        2785280    2                       
0x01070000 147423238  root       666        360448     2                       
0x01080000 147456007  root       666        90112      2   

2.删除系统中的共享内存

ipcrm -m [shmid]

说明: shmid为共享内存的id

2.查看系统中全部共享内存的统计

ipcs -m -u

在linux下还可自己修改共享内存的内核配置:

#vi /etc/sysctl.conf
kernel.shmmax=15461882265
kernel.shmmin=3774873
kernel.shmall=3774873

shmmax : 配置了单个共享内存段的最大值

shmmin : 配置了单个共享内存段的最小值

shmall: 可用共享内存的总数量(页面)

需要注意的是, 在Window和Linux下共享内存的表现不一样,在Window下,只要关联共享内存的进程全部退出,即便没有正确的释放关闭,操作系统也会全部释放关闭,而在linux下 ,只有关联共享的内存的进程,有一个没有正确的释放关闭,那么这块共享内存就会一直存在,需要手动用ipcrm来删除。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值