数据段共享
数据段共享起源于Windows16位的时代,在Win16操作系统时代下,dll全局变量数据段是共享的,比如有同一个dll,名为sll.dll的16位动态库,里面有一个全局变量
Int num;
有两个操作函数:
void setnum(int newnum){
num = newnum;
}
Int getnum(void){
return num;
}
当两个16位的进程加载这个动态库时,它们的数据段是共享的!
当A进程调用setnum设置新值以后:
A:setnum(16);
B进程中调用getnum获取:
B:int b = getnum();
那么此时B进程获取到的是A进程刚刚修改的值:16
双方可以很快完成进程间的通讯!
但是到了win32以后,这种方法被删除了,但是被保留到编译器命令当中了!
#pragma data_seg
预处理指令
#pragma data_seg的使用方法如下:
#pragma data_seg(“mydate”)
Int num = 0;
#pragma data_seg()
注意必须是全局的,并且变量必须显示初始化,如果不初始化,编译器会自动帮你赋值0然后放到.BSS段里去,这样就不会放到共享内存段中去了!
并且也可以使用#pragma comment预处理指令里的linker来显示规定此共享数据段的连接方法:
#pragma comment(linker,”/SECTION:mydate,RWS")
R可读性
W可写
S任意程序/文件都可以使用此共享数据段
注意前面一定要加上/SECTION:这是来表明区段的,不然编译器不认!
而且此方法还可以用来检测当前程序在同一电脑上运行了多少个!
#pragma data_seg("flag_data")int app_count = 0;#pragma data_seg()#pragma comment(linker,”/SECTION:flag_data,RWS") BOOL WINAPI DllMain( _In_ HINSTANCE hinstDLL, // 指向自身的句柄 _In_ DWORD fdwReason, // 调用原因 _In_ LPVOID lpvReserved // 隐式加载和显式加载 ){ if(app_count>0) // 如果计数大于0,则退出应用程序。{//MessageBox(NULL, "已经启动一个应用程序", "Warning", MB_OK); //printf("no%d application", app_count);return FALSE;}else{//计数+1app_count++; } }
有的dll可能不用dllmain函数,所以可以增加两个接口:
#pragma data_seg("flag_data")int app_count = 0;#pragma data_seg()#pragma comment(linker,”/SECTION:flag_data,RWS”) void add(){ app_count++; } int returnapp(){ return app_count; }
然后在应用程序入口使用:
int main(){ if(returnapp() > 0){ //MessageBox(NULL, "已经启动一个应用程序", "Warning", MB_OK); //printf("no%d application", app_count);return FALSE; }else{ add(); } }
或者用来判断当前系统下运行了多个此程序:
int main(){ add(); printf(“当前程序运行数量:%d”,returnapp); }
只要你显示的调用dll动态库里的函数,那么根据windows内核规则,动态库一定会被加载进来!
并且共享的数据段,不属于任何一个进程,Windows会把它独立放在一个内存段里,并维护它,然后有新的进程加载动态库时,Windows会检查dll里的共享数据段名是否已经存在,如果已经存在,则不在开辟,并且此动态库共享此段!那么问题来了,如果有两个新的动态库,并且段名一样怎么办?
答:操作系统是根据动态库名来区分此段属于那个动态库的,所以此问题无需我们关心,Wdindows会严格帮我们区分开!
使用此方法可以很轻松的实现进程间的共享数据!