初级代码游戏的专栏介绍与文章目录-CSDN博客
我的github:codetoys,所有代码都将会位于ctfc库中。已经放入库中我会指出在库中的位置。
这些代码大部分以Linux为目标但部分代码是纯C++的,可以在任何平台上使用。
这篇是重点,如何构建可扩展的数组结构。
目录
一、分块映射表
二、数组头
一、分块映射表
如果不支持增长,很简单,只需要一个全局变量存地址就可以了,不需要分块映射表。
为了支持增长,需要维护一个数组,存储每个块的ID和对应的数据范围:
struct struct_T_ARRAY_VMAP{int shm_id;//共享内存ID,第一个总是和array_head在一起,其余块只有数据T_SHM_SIZE handle_begin;//此块对应的handle范围[handle_begin,handle_end)T_SHM_SIZE handle_end;};struct struct_T_ARRAY_VMAP_S{long size;//使用的个数struct_T_ARRAY_VMAP m_vmaps[T_ARRAY_VMAP_MAX_SIZE];void clearVMAP(){memset(this, 0, sizeof(struct_T_ARRAY_VMAP_S));}bool AddVMAP(int _shm_id, T_SHM_SIZE oldCapacity, T_SHM_SIZE blocksize){if (size + 1 >= T_ARRAY_VMAP_MAX_SIZE)return false;m_vmaps[size].shm_id = _shm_id;m_vmaps[size].handle_begin = oldCapacity;m_vmaps[size].handle_end = oldCapacity + blocksize;++size;return true;}};
注意,分块映射表是共享内存数据头的一部分,共享内存ID和地址的关系在私有内存存储(要深刻理解哪些属于“共享”、哪些属于私有)。
T_ARRAY_VMAP_MAX_SIZE是个宏,定义最大分块数。
分块映射表不复杂,只是个定长数组,带有有效数据个数。
从可伸缩性的角度,数组长度也可以放在数据里面,这样如果修改了数组长度仍然可以正确操作,只不过相对于实际的数据量(百万千万以上级,数据很少就没必要用共享内存),这点空间微不足道,直接设置到足够大就可以了。毕竟,系统能支持的共享内存块数量和共享内存总量都是很有限的。
二、数组头
数组头需要包含足够信息让程序连接到共享内存后能正确访问数据,数组头里的灵活信息越多,兼容性越好,当然程序也越复杂。
数组头结构:
struct array_head_new{CMeta meta;sstring<64> name;T_SHM_SIZE capacity;T_SHM_SIZE size;struct_T_ARRAY_VMAP_S vmaps;//分块影射表long ____;//用来确保array_head用8字节对齐T_USER_HEAD userhead;};
这是新版数组头,所以名字带个“new”。
CMeta,是元数据描述结构,一个256字节的数据,包含全球唯一ID、字节序、int大小等信息。详见我的相关文章。
sstring<64> name,这是共享内存的名字,预定义的。名字和ID对应,但ID只在程序的私有内存使用,不进入共享内存。
容量、大小,总的容量和大小。
分块映射表,前面已经介绍过。数组头仅仅出现在第一个块,后续的块只有数据。
long ____,这是一个无意义的数据,仅仅用来保证按照long来对齐。(这可能是个BUG,因为以前仅仅在64位的linux上运行,long就是8字节,但其他系统未必如此)
T_USER_HEAD userhead,用户提供的数据头。整个系统是基于模板的,这个类型来自模板参数。
(这里是结束)