#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.
#pragma data_seg的更多相关文章
- #pragma data_seg 共享数据区(转)
原文地址:http://www.cnblogs.com/CBDoctor/archive/2013/01/26/2878201.html 1)#pragma data_seg()一般用于DLL中.也就 ...
- #pragma data_seg() 共享数据// MyData段 // 进程 // DLL
https://www.cnblogs.com/dongsheng/p/4476157.html http://www.cnblogs.com/CBDoctor/archive/2013/01/26/ ...
- 进程共享变量#pragma data_seg用法
#pragma data_seg介绍 用#pragma data_seg建立一个新的数据段并定义共享数据,其具体格式为: #pragma data_seg ("shareddata" ...
- pragma
在所有的预处理指令中,#pragma指令可能是最复杂的了,它的作用是设定编译器的状态或者是指示编译器完成一些特定的动作.#pragma指令对每个 编译器给出了一个方法,在保持与C和C++语言完全兼容的 ...
- #pragma预处理指令讲解
在所有的预处理指令中,#Pragma 指令可能是最复杂的了,它的作用是设定编译器的状态或者是指示编译器完成一些特定的动作.#pragma指令对每个编译器给出了一个方法,在保持与C和C++语言完全兼容的 ...
- #pragma alloc_text 与 ALLOC_PRAGMA
百度标题中的两部分,可以找到很多文章,现将收集到的其中两篇整理如下: 转载链接:http://hi.baidu.com/billbeggar/item/c378e2ea39a5daeffa42bada ...
- C++ #pragma 预处理指令
#pragma 预编译指令的作用是设定编译器的状态或者是指示编译器完成一些特定的动作.#pragma指令对每个编译器给出了一个方法,在保持与C和C++语言完全兼容的情况下,给出主机或操作系统专有的特征 ...
- 预处理指令中#Pragma
在所有的预处理指令中,#Pragma 指令可能是最复杂的了,它的作用是设定编译器的状态或者是指示编译器完成一些特定的动作.#pragma指令对每个编译器给出了一个方法,在保持与C和C++语言完全兼容的 ...
- #pragma的用法
在所有的预处理指令中,#Pragma 指令可能是最复杂的了,它的作用是设定编译器的状态或者是指示编译器完成一些特定的动作.#pragma指令对每个编译器给出了一个方法,在保持与C和 C++语言完全 ...
随机推荐
- HttpClient使用详解 (一)
Http协议的重要性相信不用我多说了,HttpClient相比传统JDK自带的URLConnection,增加了易用性和灵活性(具体区别,日后我们再讨论),它不仅是客户端发送Http请求变得容易,而且 ...
- JVM知识(下)
目录 方法区 类型信息 方法信息 类变量 引用类的类加载 类引用 堆(Heap) GC 定义对象 数组引用 栈 栈帧 操作数栈 帧数据 本次主要介绍,JVM的方法区,堆,栈.以下内容主要还是参考< ...
- Zookeeper--java操作zookeeper
如果是使用java操作zookeeper,zookeeper的javaclient 使我们更轻松的去对zookeeper进行各种操作,我们引入zookeeper-3.4.5.jar 和 zkclien ...
- 城市规模越大,工资、GDP、犯罪率越高:4.5星|《规模》
规模 信息浓度非常高的一本书.篇幅也不小,纸书有568页,致谢与注释只占7%. 全书讲各种复杂的东西中存在的普遍规律:哺乳动物体重每增加一倍,心率降低25%:城市人口每增加一倍,加油站只增加85%:城 ...
- JavaScript学习笔记(二)——函数和数组
第二章 函数简介 1 第一个函数示例 <script language="JavaScript" type="text/JavaScript"> f ...
- HTML(1)简介
"超"文本标记语言--HTML 文本,是指书面语言的表现形式. 百度百科 说白了,文本就是你能看得到的字,不论是纸上的还是屏幕上的,都是文本.文本就是用来记录信息一种形式. 那么, ...
- 你用 Python 做过什么有趣的数据挖掘项目?
有网友在知乎提问:「你用 Python 做过什么有趣的数据挖掘项目?」 我最近刚开始学习 Python, numpy, scipy 等, 想做一些数据方面的项目,但是之前又没有这方面的经验.所以想知道 ...
- Python常用模块之hashlib
Python里面的hashlib模块提供了很多加密的算法,这里介绍一下hashlib的简单使用事例,用hashlib的md5算法加密数据 import hashlib hash = hashlib.m ...
- 扩展Lucas定理 扩展Lucas板子
题意概述:多组询问,给出N,K,M,要求回答C(N,K)%M,1<=N<=10^18,1<=K<=N,2<=M<=10^6 分析: 模数不为质数只能用扩展Lucas ...
- 由A到D中间可不止“B、C”
在电子信息系统的学习中,我们或许早就被告知现实世界是模拟的,而数字化的模拟世界则越来越展现更多的风采.但是所谓的数字和模拟只是相对的而已,你可以把模拟量当做无穷数字量的组合,也可以把数字量当做具有不同 ...