Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1334185
  • 博文数量: 436
  • 博客积分: 7854
  • 博客等级: 少将
  • 技术积分: 3225
  • 用 户 组: 普通用户
  • 注册时间: 2007-12-18 16:30
文章分类

全部博文(436)

文章存档

2013年(2)

2012年(56)

2011年(70)

2010年(308)

分类:

2010-07-13 11:41:34

Dll的各进程之间共享-#pragma data_seg预处理指令用于设置共享数据段
 


在Win16环境中,DLL的全局数据对每个载入它的进程来说都是相同的;而在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"),那么这个数据节中的数据可以在所有DLL的实例之间共享。所有对这些数据的操作都针对同一个实例的,而不是在每个进程的地址空间中都有一份。
   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!这就实现了跨进程之间的数据通信!

下面看一个实际应用,用共享数据来统计应用程序启动的次数,并作相应的处理。

在应用程序的入口处:
//控制应用程序只能启动一次
#pragma data_seg("flag_data")
   int count=0;
#pragma data_seg()
#pragma comment(linker,"/SECTION:flag_data,RWS")
程序中:
   if(count>1)
     {
      MessageBox("已经启动了一个应用程序","Warning",MB_OK);
      return FLASE;
}
   count++;
-----------------------------------------------------------

概要

Win 32 动态链接库 (DLL) 默认,这意味着使用 DLL 的每个应用程序获取它自己的 DLL 的数据的副本的情况下使用实例数据。 但是,就可以共享 DLL 数据之间所有使用该 DLL 的应用程序。

如果您需要共享仅部分 DLL 数据,Microsoft 建议创建一个新的节和而共享它。 如果您想共享的所有 DLL 静态数据,非常重要做两件事情:
第一次,DLL 必须使用 C 运行时的 DLL 版本 (例如 Crtdll.lib 或 Msvcrt.lib)。 请参阅您的产品文档更多有关使用 C 运行时 DLL 中。

注意: Crtdll.lib 不再 SDK,从 Windows NT 3.51 开始的一部分。 上次发布年 4 月 1995 年上的 MSDN 3.5 SDK。 Win 32 现在要求用户指定的由他们自己的编译器 vender 提供的 C 运行时 LIBs 他们自己的版本。
第二个,您需要指定.data 和.bss 共享。 通常,这样.def 文件的"SECTIONS"部分中。 例如:
   SECTIONS
.bss READ WRITE SHARED
.data READ WRITE SHARED
如果您要使用 Visual C++ 32-bit Edition,您必须指定此使用链接器上的部分开关。 例如:
link -section:.data,rws -section:.bss,rws
只有静态数据被共享。 用对作为 GlobalAlloc() 和 malloc() 这样的 API / 函数的调用动态分配的内存是仍然特定于调用进程。

系统试图加载每个进程中相同的地址处共享的内存块。 但是,如果块不能将加载到相同的内存地址,系统将共享的分区映射到一个不同的内存地址。 仍在共享内存。 请注意该共享节内部指针无效在这种情况下并不能放共享各节中。

更多信息

C 运行时使用全局变量。 如果 CRT 是静态与该 DLL,链接这些变量将在 DLL 的所有客户端之间共享并将最有可能导致的异常 c 0000005。

您要同时指定.data 和.bss 为共享,因为它们每个保存不同类型的数据。 .data 部分包含初始化的数据,.bss 部分保存未初始化的数据。

for sharing in DLL all data one reason is to have in between Win32 DLL (running on Windows NT) and Win32s consistent behavior (running on Windows 3.1). when running on Win32s,32-bit DLL shares among all of that use DLL processes its data。

请注意不需要共享所有数据 Win 32 和 Win32s 之间的行为完全相同。 DLL 可用于将变量存储为实例数据在 Win 32 线程本地存储 (TLS)。

for additional information,please see following article in Microsoft Knowledge Base:
() 在一个 Win 32 中创建实例数据 DLL
阅读(702) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~