写时拷贝技术与共享节
一、写时拷贝技术
当为正在运行的应用程序创建新进程时,系统将打开用于表示可执行文件映射文件的文件映射对象的另一个内存映射视图,并创建一个新进程对象和一个新线程对象,同时将新进程ID和新线程ID赋予这些对象,通过内存映射文件,同一个应用程序的多个正在运行的实例(进程)共享RAM中相同的代码和数据,大大的提高了系统的性能。但是这要求所有实例都将该内存是只读或只执行的,否则,其他实例看到的这个内存也将被修改,操作系统使用写时拷贝技术来解决这个问题。
写时拷贝技术是指操作系统给共享内存块赋予Copy-On-Write保护属性,当一个进程中的线程尝试将数据写入他的内存映射文件是,系统将俘获这种异常,为包含应用程序尝试写入数据的内存页面分配一个新内存块,将修改地址映射到新分配的页面上,拷贝该页面的内容,并允许该线程将数据写入新分配的内存块,此时,同一个应用程序的所有其他实例运行都不受影响。
写时拷贝拷贝技术提高了系统的安全性,同时也使得可执行文件或DLL的多个实例不能共享静态数据。
二、多实例共享静态数据技术
某些情况下,一个.exe文件的多个映像共享一个变量的实例是非常有用和方便的,如确定系统中是否运行着某个应用程序的多个实例等。
我们可以通过共享数据节的方法来解决可执行文件的运行的多个实例不能共享静态数据的问题,从PE文件结构中我们可以了解到,每个.exe或dll文件的映像由许多节组成,如代码节(.text)、已初始化数据节(.data)、未初始化数据节(.bss)、输入文件名表(.idata)、输出文件名表(.edata)等。更多的PE文件结构内存参见“PE文件结构”一文。
除了编译器和连接程序创建的标准节外,可以创建自己的节,并设置节的保护属性,当将节的保护属性设置为共享时,多个应用程序的实例将可以共享该节中的数据。
三、创建并使用节
1、 创建节
#pragma data_seg("Shared")
bool isExist = false; /*已经初始化变量*/
int num1; /*未初始化变量*/
#pragma data_seg()
注:在创建节的过程中,编译器只将已经初始化的变量放入新节中。
2、 将初始化或未初始化的数据放入希望的任何节中
__declspec(allocate("Shared")) int num2 = 0; /*添加初始化的变量*/
__declspec(allocate("Shared")) int num3; /*添加未初始化的变量*/
注:在向节中添加数据之前必须先创建该节。
3、 设置节的属性
#pragma comment(linker, "/Section:Shared,RWS")
注:节的属性包括RWS,其中R代表READ,W代表WEITE,S代表SHARED。
验证程序:
#include <iostream>
using namespace std;
/*创建自定义的数据节*/
#pragma data_seg("Shared")
bool isExist = false; /*已经初始化变量,在节中,可共享*/
int num1; /*未初始化变量,不在节中,不可共享*/
#pragma data_seg()
/*添加初始化的变量,在节中,可共享*/
__declspec(allocate("Shared")) int num2 = 0;
/*添加未初始化的变量,在节中,可共享*/
__declspec(allocate("Shared")) int num3;
int num4 = 0; /*普通全局变量,无法共享*/
/*设置共享数据节的属性*/
#pragma comment(linker, "/Section:Shared,RWS")
void main()
{
if(!isExist)
{
isExist = true;
num1 = 1;
num2 = 2;
num3 = 3;
num4 = 4;
cout << "This is the first instance !" << endl;
}
else
{
cout << "This is not the first instance !" << endl;
}
cout << "num1 : " << num1 << endl;
cout << "num2 : " << num2 << endl;
cout << "num3 : " << num3 << endl;
cout << "num4 : " << num4 << endl;
system("pause");
}
输出结果:
第一次执行:
This is the first instance !
num1 : 1
num2 : 2
num3 : 3
num4 : 4
第二次执行:
This is not the first instance !
num1 : 0
num2 : 2
num3 : 3
num4 : 0