您的位置:首页 > 编程语言 > C语言/C++

事件和进程间的数据交换 . 分类: VC++ 2013-10-09 11:47 585人阅读 评论(0) 收藏

2013-10-09 11:47 501 查看
//========================================================================

//TITLE:

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

//AUTHOR:

// norains

//DATE:

// Monday 13-July-2009

//Environment:

// WINCE5.0 + VS2005

//========================================================================

多线程的数据交流不难,毕竟是同属于一个进程,更为重要的是,代码还很可能同属于一个工程,基本上想怎么干就怎么干,大不了我用一个全局变量来做缓存来进行数据的交换。

但对于多进程来说,就没那么容易了。从代码的角度来说,多进程意味不同的工程,意味着不能简单通过全局变量来交流数据。试想一下,如果IE有一个全局变量g_iCurPage,你用什么方法才能得到该数据?因此,在多进程的情况下,多线程那一套就没辙了。

不过,如果只是交流数据,情况倒不显得那么糟糕。一般的流程无非就是:假设有两个,分别是进程A和进程B,当线程A改变某些数值时,它会通过发送相应的事件给进程B;进程B在获得该通知事件后,会采取一定的方式,读取进程A所改变的数值。

听起来是不是很简单?

在讨论这个问题之前,我们先假设这两个进程存在如下架构的代码。

[cpp]
view plaincopyprint?

进程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:获取相应的数据
}
}
}

[cpp]
view plaincopyprint?

进程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:
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?

进程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);
}

[cpp]
view plaincopyprint?

进程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);
}
}
}

进程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等结构体数值了。不过,这却是这三种方法之中,和事件联系最为紧密的。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐