当前位置: 首页 > news >正文

5、在共享内存无指针编程:句柄HANDLE转换为指针

初级代码游戏的专栏介绍与文章目录-CSDN博客

我的github:codetoys,所有代码都将会位于ctfc库中。已经放入库中我会指出在库中的位置。

这些代码大部分以Linux为目标但部分代码是纯C++的,可以在任何平台上使用。


        共享内存里面不能用指针,只能用索引,在windows上经常称之为句柄(当然实际上句柄也并非索引,而是个抽象ID),我在这个系统里使用HANDLE这个名字(因为我是windows出身)。

        但是我们真的要无指针编程吗?那还要什么++?

目录

一、索引如何转换为指针

二、句柄结构

三、代码解读


一、索引如何转换为指针

        没有指针当然是很困难的,不过我们是C++啊,我们可以把索引包装得跟指针差不多。

        但是索引只有一个整数偏移量,而转为指针必须知道起始地址,怎么传递起始地址?增加参数还能当指针使用吗?这要怎么搞呢?

        但是我们是共享内存呀!共享内存是公共资源,不可能随意创建,系统内的共享内存都是被管理的,我们只需要给每个共享内存一个唯一的名字,用全局变量保存其起始地址,那么就可以把索引转换为指针而不需要额外的参数了。(这算是一个花招吧)

        前面介绍共享内存管理接口的时候,提到了共享内存的名字,除了名字,还有一个PI(指针索引),每个共享内存块都有预定义的唯一的名字和索引,另外有一个全局数组存储共享内存入口地址。

二、句柄结构

	template<typename T, int PI_N >struct T_HANDLE_ARRAY{T_SHM_SIZE handle;T_HANDLE_ARRAY(T_SHM_SIZE h = -1) :handle(h) {}T_HANDLE_ARRAY(T_HANDLE_ARRAY const& tmp) :handle(tmp.handle) {}typedef random_access_iterator_tag iterator_category;typedef T* pointer;typedef T element_type;typedef T value_type;typedef long difference_type;typedef long offset_type;typedef T& reference;bool operator<(T_HANDLE_ARRAY const& tmp)const { return handle < tmp.handle; }T_HANDLE_ARRAY operator + (long n)const{T_HANDLE_ARRAY tmp;tmp.handle = handle + n;return tmp;}T_HANDLE_ARRAY operator - (long n)const{T_HANDLE_ARRAY tmp;tmp.handle = handle - n;return tmp;}T_SHM_SIZE operator - (T_HANDLE_ARRAY const& tmp)const { return handle - tmp.handle; }T_HANDLE_ARRAY& operator += (T_SHM_SIZE n) { handle += n; return *this; }T_HANDLE_ARRAY& operator ++ () { ++handle; return *this; }T_HANDLE_ARRAY& operator -- () { --handle; return *this; }T_HANDLE_ARRAY& operator = (T_HANDLE_ARRAY const& tmp) { handle = tmp.handle; return *this; }bool operator == (T_HANDLE_ARRAY const& tmp)const { return handle == tmp.handle; }bool operator != (T_HANDLE_ARRAY const& tmp)const { return !((*this) == tmp); }T& operator * ()const{return *operator ->();}T* operator -> ()const{if (0 == PI_N)throw "SHM PI_N=0";struct_T_ARRAY_VMAP_S* pvmap = (struct_T_ARRAY_VMAP_S*)GET_PP_VMAP(PI_N);shm_private_data* paddrmap = &GET_SHM_PRIVATE_DATA(PI_N);for (long i = 0; i < pvmap->size; ++i){if (pvmap->m_vmaps[i].handle_begin <= handle && handle < pvmap->m_vmaps[i].handle_end){if (pvmap->size > paddrmap->addr_map_size){if (0 != paddrmap->thread_mutex.lock())throw "paddrmap->thread_mutex.lock error";if (pvmap->size > paddrmap->addr_map_size){for (long j = paddrmap->addr_map_size; j < pvmap->size; ++j){char* p = CShmMan::ConnectByID(pvmap->m_vmaps[j].shm_id, false);if (NULL == p){thelog << "连接共享内存失败 shmid = " << pvmap->m_vmaps[j].shm_id << " 错误信息:" << strerror(errno) << ende;throw "连接共享内存失败";}if (((unsigned long)p) % 8 != 0){thelog << "地址对齐错误" << ende;throw "地址对齐错误";}char buf[256];sprintf(buf, "连接共享内存 %d %ld shm_id %d addr %p", PI_N, j, pvmap->m_vmaps[j].shm_id, p);thelog << buf << endi;paddrmap->AddShmMap(pvmap->m_vmaps[j].shm_id, p);}}else{thelog << "已经被其它线程处理" << endi;}if (0 != paddrmap->thread_mutex.unlock())throw "paddrmap->thread_mutex.unlock error";}return (T*)paddrmap->shm_addr_map[i].second + handle - pvmap->m_vmaps[i].handle_begin;}if (i == pvmap->size - 1 && handle == pvmap->m_vmaps[i].handle_end){thelog << "刚好越过最后一个 " << handle << " " << (T*)paddrmap->shm_addr_map[i].second + handle - pvmap->m_vmaps[i].handle_begin << endi;//return (T *)paddrmap->shm_addr_map[i].second+handle-pvmap->m_vmaps[i].handle_begin;}}char buf[2048];sprintf(buf, "->无效的句柄 PI_N=%d handle=%ld", PI_N, handle);theLog << "shmArray.h T_HANDLE_ARRAY" << buf << ende;ShowVMapPrivateData();abort();return NULL;}static T_SHM_SIZE _me(T const* p, bool not_throw = false){char buf[256];struct_T_ARRAY_VMAP_S* pvmap = (struct_T_ARRAY_VMAP_S*)GET_PP_VMAP(PI_N);shm_private_data* paddrmap = &GET_SHM_PRIVATE_DATA(PI_N);for (long i = 0; i < pvmap->size; ++i){if ((T*)paddrmap->shm_addr_map[i].second <= p && p < (T*)paddrmap->shm_addr_map[i].second + pvmap->m_vmaps[i].handle_end - pvmap->m_vmaps[i].handle_begin){return p - (T*)paddrmap->shm_addr_map[i].second + pvmap->m_vmaps[i].handle_begin;}if (i == pvmap->size - 1 && p == (T*)paddrmap->shm_addr_map[i].second + pvmap->m_vmaps[i].handle_end - pvmap->m_vmaps[i].handle_begin){thelog << "刚好越过最后一个 " << p << " " << p - (T*)paddrmap->shm_addr_map[i].second + pvmap->m_vmaps[i].handle_begin << endi;//return p-(T *)paddrmap->shm_addr_map[i].second+pvmap->m_vmaps[i].handle_begin;}}if (not_throw)return -1;else{sprintf(buf, "_me无效的地址 %p", p);throw buf;}}static void ShowVMapPrivateData(){struct_T_ARRAY_VMAP_S* pvmap = (struct_T_ARRAY_VMAP_S*)GET_PP_VMAP(PI_N);shm_private_data* paddrmap = &GET_SHM_PRIVATE_DATA(PI_N);long i, j;theLog << endl;theLog << "pvmap->size=" << pvmap->size << endl;for (i = 0; i < pvmap->size; ++i){theLog << i << " : begin=" << pvmap->m_vmaps[i].handle_begin << " end=" << pvmap->m_vmaps[i].handle_end << endl;}theLog << "paddrmap->addr_map_size=" << paddrmap->addr_map_size << endl;for (j = 0; j < paddrmap->addr_map_size; ++j){theLog << j << " : " << paddrmap->shm_addr_map[j].first << " - " << (long)paddrmap->shm_addr_map[j].second << endl;}theLog << endi;}};

三、代码解读

        这个代码是个模板,参数是指向的类型和入口指针的索引。

        主要部分是自定义的指针类,符合随机迭代器概念要求,可以用在STL算法里。

        复杂的代码部分是在没有连接是自动去连接。由于每个共享内存结构其实是可扩展的,是多个共享内存的串联,因此代码比较复杂。数据的索引是连续的,但不同分块的连接地址并不相同,因此需要一个分块映射表。还要考虑多线程保护。如果没有分块问题,操作会简单很多,只需要根据PI_N获取入口地址,判断是否需要连接,然后就能转换为指针了。


(这里是文档结束)

http://www.lryc.cn/news/402792.html

相关文章:

  • hive动态分区导致xceivercount超限,hdfs无法创建新连接
  • 如何识别Android init 中的缓慢操作
  • JVM:常用工具总结
  • 二染色,CF 1594D - The Number of Imposters
  • Go语言并发编程-Channel通信_2
  • Richteck立锜科技电源管理芯片简介及器件选择指南
  • Socket 简介与 Java Socket 编程示例
  • 跟着操作,解决iPhone怎么清理内存难题
  • React、Vue的password输入框组件,如何关闭自动填充?
  • HTML+JS+CSS计算练习
  • 设计模式使用场景实现示例及优缺点(行为型模式——责任链模式)
  • CSS-1_0 CSS和文档流
  • 小程序图片下载保存方法,图片源文件保存!
  • 新书速览|深入理解Hive:从基础到高阶:视频教学版
  • 钡铼Profinet、EtherCAT、Modbus、MQTT、Ethernet/IP、OPC UA分布式IO系统BL20X系列耦合器
  • Git分支合并以及分支部分合并 提交记录合并
  • IDEA关联数据库
  • 【Leetcode】14. 最长公共前缀
  • 【BUG】已解决:zipfile.BadZipFile: File is not a zip file
  • 小白新手搭建个人网盘
  • NineData全面支持PostgreSQL可视化表结构设计
  • 从系统层面认识Linux及mysql中的多表查询
  • PCB(印制电路板)制造涉及的常规设备
  • 《Windows API每日一练》10.3 公用对话框
  • C++中的引用
  • 【自学安全防御】三、企业双机热备和带宽管理的综合实验
  • 无极与有极电容的区别
  • 入坑树莓派(2)——树莓派4B与手机蓝牙通信
  • RocketMQ单结点安装/Dashboard安装
  • 【北京迅为】《i.MX8MM嵌入式Linux开发指南》-第二篇 Linux系统编程篇-第三十四章 进程基础