事件和进程间的数据交换 .

//========================================================================
//TITLE:
//    事件和进程间的数据交换
//AUTHOR:
//    norains
//DATE:
//    Monday  13-July-2009
//Environment:
//    WINCE5.0 + VS2005
//========================================================================
    多线程的数据交流不难,毕竟是同属于一个进程,更为重要的是,代码还很可能同属于一个工程,基本上想怎么干就怎么干,大不了我用一个全局变量来做缓存来进行数据的交换。
   
    但对于多进程来说,就没那么容易了。从代码的角度来说,多进程意味不同的工程,意味着不能简单通过全局变量来交流数据。试想一下,如果IE有一个全局变量g_iCurPage,你用什么方法才能得到该数据?因此,在多进程的情况下,多线程那一套就没辙了。
   
    不过,如果只是交流数据,情况倒不显得那么糟糕。一般的流程无非就是:假设有两个,分别是进程A和进程B,当线程A改变某些数值时,它会通过发送相应的事件给进程B;进程B在获得该通知事件后,会采取一定的方式,读取进程A所改变的数值。

    听起来是不是很简单?
   
    在讨论这个问题之前,我们先假设这两个进程存在如下架构的代码。

[cpp] view plaincopyprint?

  1. 进程A:  
  2. DWORD NotifyProc(LPVOID pParam)  
  3. {  
  4.  while(TRUE)  
  5.  {  
  6.   if(IsDataChange() != FALSE)  
  7.   {  
  8.    //TODO:准备好传送的数据   
  9.      
  10.    PulseEvent(hEventNotify);         
  11.   }  
  12.  }  
  13. }  
  14.   
  15. 进程B:  
  16. DWORD WaitNotifyProc(LPVOID pParam)  
  17. {  
  18.  while(TRUE)  
  19.  {  
  20.   DWORD dwReturn = WaitForSingleObject(hEventNotify);  
  21.   if(dwReturn != WAIT_TIMEOUT)  
  22.   {  
  23.    //TODO:获取相应的数据   
  24.   }  
  25.  }  
  26. }  

进程A:
DWORD NotifyProc(LPVOID pParam)
{
while(TRUE)
{
if(IsDataChange() != FALSE)
{
//TODO:准备好传送的数据

PulseEvent(hEventNotify);
}
}
}

进程B:
DWORD WaitNotifyProc(LPVOID pParam)
{
while(TRUE)
{
DWORD dwReturn = WaitForSingleObject(hEventNotify);
if(dwReturn != WAIT_TIMEOUT)
{
//TODO:获取相应的数据
}
}
}

 

    从这段简单的代码之中,我们可以知道有这么两个难点,首先是进程A如何准备数据,其次便是进程B如何获取进程A准备的数据。
   
    接下来要论述的方式,都是基于这个框架的两个难点来讨论。   
   
    一般的做法,无非有三种。   
   
1).注册表
   
    采用该方式后完善的代码如下:

[cpp] view plaincopyprint?

  1. 进程A:  
  2. DWORD NotifyProc(LPVOID pParam)  
  3. {  
  4.  while(TRUE)  
  5.  {  
  6.   if(IsDataChange() != FALSE)  
  7.   {  
  8.    //更改相应的注册表数值   
  9.    CReg reg;  
  10.    reg.Create(HKEY_CURRENT_USER,DEVICE_INFO);  
  11.    reg.SetDW(MAIN_VOLUME,dwVal);  
  12.    reg.Close();  
  13.      
  14.    //发送通知事件   
  15.    PulseEvent(hEventNotify);         
  16.   }  
  17.  }  
  18. }  
  19.   
  20. 进程B:      
  21. DWORD WaitNotifyProc(LPVOID pParam)  
  22. {  
  23.  while(TRUE)  
  24.  {  
  25.   //等待通知事件   
  26.   DWORD dwReturn = WaitForSingleObject(hEventNotify);  
  27.     
  28.   if(dwReturn != WAIT_TIMEOUT)  
  29.   {  
  30.    //读取注册表   
  31.    CReg reg;  
  32.    reg.Create(HKEY_CURRENT_USER,DEVICE_INFO);  
  33.    DWORD dwVal = 0;  
  34.    dwVal = reg.GetDW(MAIN_VOLUME);  
  35.   }  
  36.  }  
  37. }  

进程A:
DWORD NotifyProc(LPVOID pParam)
{
while(TRUE)
{
if(IsDataChange() != FALSE)
{
//更改相应的注册表数值
CReg reg;
reg.Create(HKEY_CURRENT_USER,DEVICE_INFO);
reg.SetDW(MAIN_VOLUME,dwVal);
reg.Close();

//发送通知事件
PulseEvent(hEventNotify);
}
}
}

进程B:
DWORD WaitNotifyProc(LPVOID pParam)
{
while(TRUE)
{
//等待通知事件
DWORD dwReturn = WaitForSingleObject(hEventNotify);

if(dwReturn != WAIT_TIMEOUT)
{
//读取注册表
CReg reg;
reg.Create(HKEY_CURRENT_USER,DEVICE_INFO);
DWORD dwVal = 0;
dwVal = reg.GetDW(MAIN_VOLUME);
}
}
}

 

    该方法灵活性非常高,进程A如果想增加更多的通知数据,只需要简单地多设注册表项。而进程B可以不用管进程A设置了多少注册表项,只需要获取自己所需要的项目即可。

    另外一个更为明显的优势在于,由于该方法是将数据保存于注册表,所以在进程B的运行是在进程A退出之后,进程B还能获取数据。甚至于,机器重启后,进程B依然能获取相应数据——前提条件是系统的注册表为Hive Registry。

    如果说缺陷,确切地说是相对于另外两种方法而言,便是速度。因为期间会对注册表进行读写,所以速度会略有损失。如果对速度非常在意,那么该方法并不是最理想的。

2).内存印射

    其实这种方式在我blog的另一篇文章《进程间的数据共享》(http://blog.csdn.net/norains/archive/2008/07/16/2663390.aspx)有提过,但为了本篇的完整性,在这里根据我们的论述框架重新来讨论一次。
   
    原理很简单,进程A先调用CreateFileMapping开辟一个印射的内存区,然后往里面拷贝数据,最后通知进程B读取数据;进程B接受通知时,就直接调用memcpy从内存中获取数据。

[cpp] view plaincopyprint?

  1. 进程A:  
  2. DWORD NotifyProc(LPVOID pParam)  
  3. {  
  4.  //创建内存文件印射   
  5.  HANDLE hFile = CreateFileMapping((HANDLE)-1,NULL,PAGE_READWRITE,0,MEM_SIZE,MEM_SHARE_NAME);  
  6.    
  7.  VOID * pMem = NULL;  
  8.  if(hFile != NULL)  
  9.  {  
  10.   pMem = MapViewOfFile(hFile,FILE_MAP_ALL_ACCESS,0,0,0);  
  11.  }  
  12.   
  13.  while(TRUE)  
  14.  {  
  15.   if(IsDataChange() != FALSE)  
  16.   {  
  17.    //拷贝传输的数据   
  18.    if(pMem != NULL)  
  19.    {  
  20.     memcpy(pMem,&dwValue,sizeof(dwValue));  
  21.    }  
  22.      
  23.    PulseEvent(hEventNotify);         
  24.   }  
  25.  }  
  26.    
  27.  //如果不再使用,应该关闭句柄   
  28.  CloseHandle(hFile);  
  29.   
  30. }  
  31.   
  32. 进程B:  
  33. DWORD WaitNotifyProc(LPVOID pParam)  
  34. {  
  35.  //创建内存文件印射   
  36.  HANDLE hFile = CreateFileMapping((HANDLE)-1,NULL,PAGE_READWRITE,0,MEM_SIZE,MEM_SHARE_NAME);  
  37.    
  38.  VOID * pMem = NULL;  
  39.  if(hFile != NULL)  
  40.  {  
  41.   pMem = MapViewOfFile(hFile,FILE_MAP_ALL_ACCESS,0,0,0);  
  42.  }  
  43.    
  44.  while(TRUE)  
  45.  {  
  46.   DWORD dwReturn = WaitForSingleObject(hEventNotify);  
  47.   if(dwReturn != WAIT_TIMEOUT)  
  48.   {  
  49.    //拷贝传输过来的数据   
  50.    if(pMem != NULL)  
  51.    {  
  52.     memcpy(&dwValue,pMem,sizeof(dwValue));  
  53.    }  
  54.   }  
  55.  }  
  56.    
  57.  //如果不再使用,应该关闭句柄   
  58.  CloseHandle(hFile);  
  59. }  

进程A:
DWORD NotifyProc(LPVOID pParam)
{
//创建内存文件印射
HANDLE hFile = CreateFileMapping((HANDLE)-1,NULL,PAGE_READWRITE,0,MEM_SIZE,MEM_SHARE_NAME);

VOID * pMem = NULL;
if(hFile != NULL)
{
pMem = MapViewOfFile(hFile,FILE_MAP_ALL_ACCESS,0,0,0);
}

while(TRUE)
{
if(IsDataChange() != FALSE)
{
//拷贝传输的数据
if(pMem != NULL)
{
memcpy(pMem,&dwValue,sizeof(dwValue));
}

PulseEvent(hEventNotify);
}
}

//如果不再使用,应该关闭句柄
CloseHandle(hFile);

}

进程B:
DWORD WaitNotifyProc(LPVOID pParam)
{
//创建内存文件印射
HANDLE hFile = CreateFileMapping((HANDLE)-1,NULL,PAGE_READWRITE,0,MEM_SIZE,MEM_SHARE_NAME);

VOID * pMem = NULL;
if(hFile != NULL)
{
pMem = MapViewOfFile(hFile,FILE_MAP_ALL_ACCESS,0,0,0);
}

while(TRUE)
{
DWORD dwReturn = WaitForSingleObject(hEventNotify);
if(dwReturn != WAIT_TIMEOUT)
{
//拷贝传输过来的数据
if(pMem != NULL)
{
memcpy(&dwValue,pMem,sizeof(dwValue));
}
}
}

//如果不再使用,应该关闭句柄
CloseHandle(hFile);
}

 

    该方法是最复杂的,两个进程不仅协同设置内存的大小(MEM_SIZE),还要设置同样的名称(MEM_SHARE_NAME),更要判断该内存是否能分配成功。相对的,灵活性也是最高的,只要以上问题协商解决,则什么数据类型都能传递,无论是DWORD,或是struct。当然,我们还是不能传递对象指针,因为简单地传递对象指针,则基本上都会引发内存访问违例的致命错误。

3).设置事件数据

    相对于以上两种方式,该方式彻头彻尾只能属于轻量级。因为它方式最为简单,同样,所传递的数据也最少。
   
    其原理很简单,进程A通过SetEventData设置和事件关联的数据,然后发送事件通知进程B;进程B接收到进程A的事件以后,则通过GetEventData来获取数据。根据该原理,则代码的样式可以如下:

[cpp] view plaincopyprint?

  1. 进程A:  
  2. DWORD NotifyProc(LPVOID pParam)  
  3. {  
  4.  while(TRUE)  
  5.  {  
  6.   if(IsDataChange() != FALSE)  
  7.   {  
  8.    //设置关联数据   
  9.    SetEventData(hEventNotify,dwData);  
  10.      
  11.    PulseEvent(hEventNotify);         
  12.   }  
  13.  }  
  14. }  
  15.   
  16. 进程B:  
  17. DWORD WaitNotifyProc(LPVOID pParam)  
  18. {  
  19.  while(TRUE)  
  20.  {  
  21.   DWORD dwReturn = WaitForSingleObject(hEventNotify);  
  22.   if(dwReturn != WAIT_TIMEOUT)  
  23.   {  
  24.    //获取关联数据   
  25.    dwData = GetEventData(hEventNotify);  
  26.   }  
  27.  }  
  28. }  

进程A:
DWORD NotifyProc(LPVOID pParam)
{
while(TRUE)
{
if(IsDataChange() != FALSE)
{
//设置关联数据
SetEventData(hEventNotify,dwData);

PulseEvent(hEventNotify);
}
}
}

进程B:
DWORD WaitNotifyProc(LPVOID pParam)
{
while(TRUE)
{
DWORD dwReturn = WaitForSingleObject(hEventNotify);
if(dwReturn != WAIT_TIMEOUT)
{
//获取关联数据
dwData = GetEventData(hEventNotify);
}
}
}

 

    该方式是最简单的,在传递DWORD长度类型的数据有得天独厚的优势,无论是速度还是简便性。但,也仅限于此,如果想采用该方式传递大小大于DWORD的数值,基本上会丢失精度,更不用说struct等结构体数值了。不过,这却是这三种方法之中,和事件联系最为紧密的。

时间: 2024-08-01 20:25:19

事件和进程间的数据交换 .的相关文章

C++进程间共享数据实例_C 语言

本文实例讲述了C++进程间共享数据的实现方法,分享给大家供大家参考.具体实现方法如下: 复制代码 代码如下: int main(int argc, char *argv[])  {      //RecursiveDelete("C:\\20_128\\");      //SelfRun("runModel");      //进程间内存共享      LPCTSTR lpName= "hello";      LPCTSTR lpConten

C#中使用SendMessage在进程间传递数据的实例

原文:C#中使用SendMessage在进程间传递数据的实例 1 新建解决方案SendMessageExample 在解决方案下面新建三个项目:CopyDataStruct,Receiver和Sender. 其中,CopyDataStruct项目的输出类型为"类库",Receiver和Sender项目的输出类型为"Windows 应用程序". 整个实例程序的结构如下图所示.   2 CopyDataStruct项目实现 定义结构体COPYDATASTRUCT,代码如

Python multiprocessing.Manager介绍和实例(进程间共享数据)_python

Python中进程间共享数据,处理基本的queue,pipe和value+array外,还提供了更高层次的封装.使用multiprocessing.Manager可以简单地使用这些高级接口. Manager()返回的manager对象控制了一个server进程,此进程包含的python对象可以被其他的进程通过proxies来访问.从而达到多进程间数据通信且安全. Manager支持的类型有list,dict,Namespace,Lock,RLock,Semaphore,BoundedSemaph

如何实现进程间数据通讯技术

1.引言 在Windows程序中,各个进程之间常常需要交换数据,进行数据通讯.WIN32 API提供了许多函数使我们能够方便高效地进行进程间的通讯,通过这些函数我们可以控制不同进程间的数据交换,就如同在WIN16中对本地进程进行读写操作一样. 典型的WIN16两进程可以通过共享内存来进行数据交换:(1)进程A将GlobalAlloc(GMEM_SHARE...)API分配一定长度的内存:(2)进程A将GlobalAlloc函数返回的句柄传递给进程B(通过一个登录消息):(3)进程B对这个句柄调用

由一道面试题来了解进程间的通信

    周末面试碰到一个面试题,题目是: 在MMO游戏中,服务器采用Linux操作系统,网络通信与游戏逻辑处理进程一般是分离的.例如:GameSvr进程处理游戏逻辑,TCPSvr进程处理网络通信.Linux操作系统提供了很多机制可以实现GameSvr和TCPSvr进程之间的数据通信.请您列出两种你认为最好的机制来,并为主(最好)次(次佳)描述他们实现的框架,优缺点对比和应用中的注意事项. 答案:Linux下进程通信 一.进程间通信概述进程通信有如下一些目的:A.数据传输:一个进程需要将它的数据发

Visual C++进程间数据通信的实现

在Windows系统中,各个应用程序(进程)之间常常需要交换.传递数据,这就要解决进程间的数据通信问题.在最初的16位Windows3.x系统中,所有Windows应用程序共享单一地址,任何进程都能够对这一共享地址空间的数据进行读写操作.随着Windwos98.WindowsNT.Windows2000等32位的操作系统的出现,规定每个进程都有自己的地址空间,一个Windows进程不能存取另一个进程的私有数据,也就是说,虽然两个进程可以用具有相同值的指针寻址,但所读写的只是它们各自的数据,这样就

两个进程间的数据共享问题

问题描述 问题是这样的,有两个进程(或者更多的进程),启动的时候都从同一个文件读取数据,在各自的进程中建立对象模型.这两个进程还都可以修改数据.那么,问题来了,如果进程A修改了数据,进程B要适时的获得修改后的数据,应该采用什么样的解决方案来实现呢?因为程序的基础通信架构采用的是WCF,考虑过使用WCF进行通信来同步两个进程间的数据,但设计到的数据维度比较多,如果每一个属性的修改都需要来一次通信的话,这样肯定对性能就会产生很大的影响了.不知道,各位大神是否有更好的方案,烦请赐教!!!谢谢!!! 解

浅谈Delphi中进程间的数据共享

DLL是创建Windows应用程序,实现代码重用的重要手段.那么当我们需要在进程间共享数据时,怎样做才能快捷方便地实现呢?在32位应用系统中,每个应用程序会将DLL映射到自己的地址空间,同时DLL中的数据也就随之被映射了.这样,每个应用程序都有自己的数据实例,在一个应用程序中修改DLL中的全局变量,不会影响其它的应用程序.DLL的使用似乎与我们的目的相背离,那么如何才能实现我们想要的东东呢?这里给大家介绍一种特殊的技术,那就是内存映射文件. 内存映射文件提供了一种方法,就是在WIN32系统的地址

Linux 进程间通讯共享内存方式

共享内存方式:从物理内存里面拿出来一部分作为多个进程共享. 共享内存是进程间共享数据的一种最快的方法,一个进程向共享内存区域写入数据,共享这个内存的所有进程都可以立即看到其中内容. 共享内存实现步骤: 一.创建共享内存,使用shmget函数. 二.映射共享内存,将这段创建的共享内存映射到具体的进程空间去,使用shmat函数. 创建共享内存shmget: intshmget(key_t key, size_t size, int shmflg) 功能:得到一个共享内存标识符或创建一个共享内存对象并