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

#pragma data_seg 共享数据区(转)

原文地址:http://www.cnblogs.com/CBDoctor/archive/2013/01/26/2878201.html

1)#pragma data_seg()一般用于DLL中。也就是说,在DLL中定义一个共享的,有名字的数据段。最关键的是:这个数据段中的全局变量可以被多个进程共享。否则多个进程之间无法共享DLL中的全局变量。


2)共享数据必须初始化,否则微软编译器会把没有初始化的数据放到.BSS段中,从而导致多个进程之间的共享行为失败。

 

3)你所谓的结果正确是一种错觉。如果你在一个DLL中这么写:
      #pragma data_seg("MyData")
      int g_Value; // Note that the global is not initialized.
      #pragma data_seg()

DLL提供两个接口函数:

   

int GetValue()
{
      return g_Value;
}
void SetValue(int n)
{
      g_Value = n;
}

 


         启动两个进程A和B,A和B都调用了这个DLL,假如A调用了SetValue(5); B接着调用int m = GetValue(); 那么m的值不一定是5,而是一个未定义的值。因为DLL中的全局数据对于每一个调用它的进程而言,是私有的,不能共享的。假如你对g_Value进行了初始化,那么g_Value就一定会被放进MyData段中。换句话说,如果A调用了SetValue(5); B接着调用int m = GetValue();那么m的值就一定是5!这就实现了跨进程之间的数据通信!

 
       有的时候我们可能想让一个应用程序只启动一次,就像单件模式(singleton)一样,实现的方法可能有多种,这里说说#pragma data_seg来实现的方法,很是简洁便利。应用程序的入口文件前面加上
              #pragma data_seg("flag_data")
              int app_count = 0;
              #pragma data_seg()
              #pragma comment(linker,"/SECTION:flag_data,RWS")


               然后程序启动的地方加上

 

if(app_count>0)     // 如果计数大于0,则退出应用程序。
{
//MessageBox(NULL, "已经启动一个应用程序", "Warning", MB_OK); 
return FALSE;
}
app_count++;

 


      这种方法只能在没有def文件时使用,如果通过def文件进行导出的话,那么设置就要在def文件内设置而不能在代码里设置了。

SETCTIONS 
flag_data READ WRITE SHARED


在主文件中,用#pragma data_seg建立一 个新的数据段并定义共享数据,其具体格式为: 
#pragma data_seg ("shareddata") //名称可以 


//自己定义,但必须与下面的一致。 
HWND sharedwnd=NULL;//共享数据 

#pragma data_seg() 
仅定义一个数据段还不能达到共享数据的目的,还要告诉编译器该段的属性,有两种方法可以实现该目的 (其效果是相同的):

一种方法是在.DEF文件中加入如下语句: SETCTIONS shareddata READ WRITE SHARED ;

另一种方法是在项目设置链接选项(Project Setting --〉Link)中加入如下语句: /SECTION:shareddata,rws 


什么是共享数据段?为什么要用共享数据段??它有什么用途?? 
      在Win32环境中,DLL函数中的代码所创建的任何对象 (包括变量)都归调用它的线程或进程所有。当进程在载入DLL时,操作系统自动把DLL地址映射到该进程的私有空间,也就是进程的虚拟地址空间,而且也复 制该DLL的全局数据的一份拷贝到该进程空间。也就是说每个进程所拥有的相同的DLL的全局数据,它们的名称相同,但其值却并不一定是相同的,而且是互不干涉的。 
      因此,在Win32环境下要想在多个进程中共享数据,就必须进行必要的设置。在访问同一个Dll的各进程之间共享存储器是通过存储器映射文件技术 实现的。也可以把这些需要共享的数据分离出来,放置在一个独立的数据段里,并把该段的属性设置为共享。必须给这些变量赋初值,否则编译器会把没有赋初始值的变量放在一个叫未被初始化的数据段中。 #pragma data_seg预处理指令用于设置共享数据段。例如: 
    #pragma data_seg("SharedDataName")

      HHOOK hHook=NULL; //必须在定义的同时进行初始化!!!!
    #pragma data_seg() 

      在#pragma data_seg("SharedDataName")和#pragma data_seg()之间的所有变量将被访问该Dll的所有进程看到和共享。再加上一条指令#pragma comment(linker,"/section:.SharedDataName,rws"),[注意:数据节的名称is case sensitive]那么这个数据节中的数据可以在所有DLL的实例之间共享。所有对这些数据的操作都针对同一个实例的,而不是在每个进程的地址空间中都有一份。 
      那么动态连接库执行的理论依据也就是内部原理是:当进程隐式或显式调用一个动态库里的函数时,系统都要把这个动态库映射到这个进程的虚拟地址空间里(以下简称"地址空间")。这使得DLL成为进程的一部分,以这个进程的身份执行,使用这个进程的堆栈。(这项技术又叫code Injection技术,被广泛地应用在了病毒、黑客领域) 
      在具体使用共享数据段时需要注意的一些问题!

 
Win32 DLLs are mapped into the address space of the calling process. By default, each process using a DLL has its own instance of all the DLLs global and static variables. (注意: 即使是全局变量和静态变量也都不是共享的!) If your DLL needs to share data with other instances of it loaded by other applications, you can use either of the following approaches: 


· Create named data sections using the data_seg pragma. 
· Use memory mapped files. See the Win32 documentation about memory mapped files. (使用内存映射文件)


Here is an example of using the data_seg pragma: 
#pragma data_seg (".myseg") 
int i = 0; 
char a[32] = "hello world"; 
#pragma data_seg() 

data_seg can be used to create a new named section (.myseg in this example). The most typical usage is to call the data segment .shared for clarity. You then must specify the correct sharing attributes for this new named data section in your .def file or with the linker option /SECTION:.MYSEC,RWS. (这个编译参数既可以使用pragma指令来指定,也可以在VC的IDE中指定!) 


There are restrictions to consider before using a shared data segment: 
· Any variables in a shared data segment must be statically initialized(所有的变量在定义时必须被初始化). In the above example, i is initialized to 0 and a is 32 characters initialized to hello world. 
· All shared variables are placed in the compiled DLL in the specified data segment. Very large arrays can result in very large DLLs(很大的变量将会导致dll非常大). This is true of all initialized global variables. 
· Never store process-specific information in a shared data segment. Most Win32 data structures or values (such as HANDLEs) are really valid only within the context of a single process(不要将标志进程的数据放在data_seg中,例如句柄等). 
· Each process gets its own address space. It is very important that pointers are never stored in a variable contained in a shared data segment. A pointer might be perfectly valid in one application but not in another. 
· It is possible that the DLL itself could get loaded at a different address in the virtual address spaces of each process. It is not safe to have pointers to functions in the DLL or to other shared variables. 

相关文章:

  • Spring Custom Bean with BeanPostProcessor
  • LAMP架构之分离式-php-fpm
  • JQuery为元素添加样式
  • Export-XLSX PowerShell generate real Excel XLSX files without Excel and COM
  • Linux动态库搜索路径的技巧
  • 非常特别的一个动态规划新手教程
  • clustershell批量执行shell命令
  • 如何把SKYPE的发送消息由enter改为ctrl+enter?
  • 如何学习开源项目
  • OAF 中对文字实现html效果及对超级长文本实现默认换行,messageTextInput只读后内容自动换行,...
  • .NET业务框架的构建
  • sql行列转换
  • 【经验】谈谈办证的那些事,献给那些即将毕业、或孩子上学等朋友
  • Myeclipse 的hadoop环境搭建
  • 数据结构-栈
  • 《Javascript数据结构和算法》笔记-「字典和散列表」
  • 【159天】尚学堂高琪Java300集视频精华笔记(128)
  • 【MySQL经典案例分析】 Waiting for table metadata lock
  • Android开发 - 掌握ConstraintLayout(四)创建基本约束
  • Angular6错误 Service: No provider for Renderer2
  • leetcode378. Kth Smallest Element in a Sorted Matrix
  • linux安装openssl、swoole等扩展的具体步骤
  • MySQL数据库运维之数据恢复
  • python docx文档转html页面
  • React的组件模式
  • spring cloud gateway 源码解析(4)跨域问题处理
  • sublime配置文件
  • Vue--数据传输
  • vue--为什么data属性必须是一个函数
  • 二维平面内的碰撞检测【一】
  • 开源地图数据可视化库——mapnik
  • 前嗅ForeSpider采集配置界面介绍
  • 小程序 setData 学问多
  • 一个JAVA程序员成长之路分享
  • 用简单代码看卷积组块发展
  • 这几个编码小技巧将令你 PHP 代码更加简洁
  • Salesforce和SAP Netweaver里数据库表的元数据设计
  • 微龛半导体获数千万Pre-A轮融资,投资方为国中创投 ...
  • 曜石科技宣布获得千万级天使轮投资,全方面布局电竞产业链 ...
  • ​TypeScript都不会用,也敢说会前端?
  • ​低代码平台的核心价值与优势
  • # 睡眠3秒_床上这样睡觉的人,睡眠质量多半不好
  • #14vue3生成表单并跳转到外部地址的方式
  • #我与Java虚拟机的故事#连载19:等我技术变强了,我会去看你的 ​
  • #中国IT界的第一本漂流日记 传递IT正能量# 【分享得“IT漂友”勋章】
  • $(function(){})与(function($){....})(jQuery)的区别
  • $.ajax中的eval及dataType
  • (第一天)包装对象、作用域、创建对象
  • (附源码)springboot猪场管理系统 毕业设计 160901
  • (机器学习的矩阵)(向量、矩阵与多元线性回归)
  • (简单有案例)前端实现主题切换、动态换肤的两种简单方式
  • (七)Knockout 创建自定义绑定
  • (转) ns2/nam与nam实现相关的文件
  • (转)linux自定义开机启动服务和chkconfig使用方法
  • (转载)Linux 多线程条件变量同步