开篇:润墨网以专业的文秘视角,为您筛选了一篇多进程间的数据通讯方式的探讨范文,如需获取更多写作素材,在线客服老师一对一协助。欢迎您的阅读与分享!
摘要:该文介绍了Windows环境下进行多进程编程的优缺点,分析了多进程编程时进程间通信的原理和多进程中资源共享的方法。重点讨论了如何在MFC中使用COPYDATA和共享虚拟内存方法实现进程间的数据通讯。
关键词:多进程;MFC;COPYDATA;共享内存;数据通讯
中图分类号:TP311文献标识码:A文章编号:1009-3044(2012)08-1821-03
在Windows环境中,多线程编程的应用广泛,作用也很大。多进程与多线程编程相比,多进程存在系统资源占用大,启动慢,退出慢等缺点,但多进程也具有很多优点,进程的设计在彼此防护上非常严谨,即如果一个进程退出,在系统中其它进程还是可以继续执行的,这样的防护使得多进程编程比多线程编程健壮,所以在很多健壮性要求较高的系统软件中,多进程编程的方式也经常被采用。在Windows中,多线程之间数据搬移比较简单,我们可以采用消息队列,也可以采用进程间的全局变量来完成。多进程之间通信则相对来说比较复杂。[1]
1通过消息队列完成进程间数据转运
在多线程之间我们可以通过消息队列来完成数据通讯,其消息可以为系统消息也可为自定的消息。在多进程之间要通过消息队列来完成数据转运,则消息只有一个,名为WM_COPYDATA,其实它是专门用来完成线程间数据搬移的,只是该消息不管两个线程是否同属一个线程。
typedef struct tagCOPYDATASTRUCT{
ULONG_PTR dwData;
DWORD cbData;
PVOID lpData;
} COPYDATASTRUCT, *PCOPYDATASTRUCT;
在发送方,发送消息的时候必须要使用SendMessage(),不能使用PostMessage()或任何其它的变种函数如PostThreadMessage()这类函数,这是因为系统必须管理用以传递数据的缓冲区的生命周期。如果使用了PostMessage(),则数据缓冲区可能会在接收端线程处理该数据之前,被系统清除并摧毁。
下面本文将举例说明WM_COPYDATA使用方法,分为两个部分:一为接收端,二为发送端,下面通两个基于MFC对话框的程序举例说明[2]:
1)发送端部分代码
//数据发送部分
CString strOut;
GetDlgItemText(IDC_EDIT1,strOut);
COPYDATASTRUCT cds;
memset(&cds,0,sizeof(cds));
cds.dwData = 1001;
cds.cbData = strOut.GetLength()+1;
cds.lpData = (LPVOID)(LPCSTR)strOut;
CString szDisplayAppName = "testcopyDatarec";
CWnd *pDisplayWnd = CWnd::FindWindow(NULL,szDisplayAppName);
if(pDisplayWnd)
pDisplayWnd->SendMessage(WM_COPYDATA,(WPARAM)GetSafeHwnd(),(LPARAM)&cds);
//清除部分代码,只需要将COPYDATASTRUCT进行如果修改,其它部分同样处理即可
COPYDATASTRUCT cds;
memset(&cds,0,sizeof(cds));
cds.dwData = 1000;
cds.cbData = 0;
cds.lpData = NULL;
从上面的代码中我们可以看出,只要我们将想要转送的数据变为一个无类型的数据流赋予COPYDATASTRUST变量,再用SendMessage()函数发送即可,发送时要注意要获取接收端进程的应用程序名。
2)接收端部分代码
在接收端由于是接收并处理系统消息,首先则应该为窗口(线程)添加WM_COPYDATA消息响应函数,然后在消息响应函数中添加如下代码。
switch(pCopyDataStruct->dwData)
{case 1001://显示
{
CString strIn = (LPCSTR)(pCopyDataStruct->lpData);
SetDlgItemText(IDC_EDIT1,strIn);
CString strTemp;
strTemp.Format("接收数据为%d",strIn.GetLength()+1);
AfxMessageBox(strTemp);
strTemp.Format("实际传送数据为%d",pCopyDataStruct->cbData);
AfxMessageBox(strTemp);
break;
}
case 1000://清除
{CString strIn = (LPCSTR)(pCopyDataStruct->lpData);
strIn += "CLEAR";
SetDlgItemText(IDC_EDIT1,strIn);
break;
}
default:
{break;
}}
这样以来,我们可以轻松的完成多进程之间的数据交换。由于COPYDATA必须使用SendMessage()函数来完成消息发送,所以我们可以使用在一些数据交换频率不高的情况,如果数据交换频率过高,过多的使用SendMessage则可能会影响接收端消息泵对其它消息的处理,使接收端响应迟钝,影响正常使用。在这种情况下,我们则可以使用共享内存的方式来解决。
2使用共享内存完成数据通信
由于我们研制的单兵设备计算机性能不高,同时所配备的设备较多,又要求软件系统响应灵敏,系统稳定。为了提高系统的稳定性,我们将GPS,陀螺仪,激光测距机等设备的数据获取,采用进程来完成,以提高系统的高效可靠性能。同时由于数据获取的频率较高,所以在单兵设备软件系统中,我们采用共享内存的方式来完成数据交互。
在使用共享内存时,有三个步骤:(1)设定共享内存区域;(2)使用共享内存;(3)共享内存的清理。
2.1设定共享内存区域
使用CreateFileMapping()函数来创建一块具有给定名称的页面文件空间,使任何一个进程都可以根据其名称来存取到它。通过CreateFileMapping()可以产生出一个file-mapping核心对象,有了这个核心对象,再通过MapViewofFile()可以在共享内存中获得一个可用的内存指针,代码如下,
HANDLE hFileMapping;
LPDWORD pCounter;
hFileMapping = CreateFileMapping((HANDLE)0xFFFFFFFF,NULL,PAGE_READWRITE,
0,sizeof(DWORD),”ServerThreadID”);
pCounter = (LPWORD)MapViewOfFile(hFileMapping,FILE_MAP_ALL_ACCESS,0,0,0);
*pCounter = GetCurrentThreadID();
这样我们就可以把当前程序的ThreadID放置在共享内存中。
2.2将共享区域映射到其它的进程地址空间中
如果把共享内存看作是Client/Server架构,那么Server进程才应该产生并初始化共享内存。所有的Client进程都应该使用OpenFileMapping()来读取指定的共享区域,再用MapViewOfFile()函数获得共享内存的指针,以读取共享内存中内容,代码如下。
HANDLE hFileMapping;
LPDWORD pCounter;
hFileMapping = OpenFileMapping(FILE_MAP_ALL_ACCESS,TRUE,”ServerThreadID”);
pCounter = (LPWORD)MapViewOfFile(hFileMapping,FILE_MAP_ALL_ACCESS,0,0,0);
DWORD dwCurrentTheadID = *pCounter;
通过以上代码,可以读取刚才在Server进程中写入共享内存的数据,进而完成两个进程间数据的通讯。
2.3共享内存的清理
一旦完成了对共享内存的操作,应该及时的调用UnmapViewOfFile(),交出原来由MapViewOfFile()函数所获得的指针,再通过CloseHandle()关闭由CreateFileMapping()创建的file-mapping核心对象,这样就可以完成共享内存的清理工作。
通过以上的三个步骤,我们可以使用共享内存来完成进程之间的数据通讯。
3共享内存时数据的同步处理
在使用共享内存的时候,我们发现共享内存的过程,其实是一个同步读写一个file-mapping核心对象的过程,象共同读写一个文件时遇到的情况是类似的,因此在读与写的时候,我们必须要考虑数据同步的问题。由于读与写的动作在不同的进程中完成,所以最好的方法就是使用一个mutex互斥对象。例如,当写的muxtex处于lock状态时,读的操作则只能等待;待写的lock状态释放后,读的操作才能得以继续工作,相反,亦然。这样我们才能安全完成共享内存的读写操作。
4结束语
使用共享内存的方法,可以方便的完成进程间数据的搬移,但不是一个容易的事,要注意以下几点:1)尽量要使共享的数据量保持最小;2)不要把非一般类或类的集合放到共享内存中;3)严格的定义存取边界,不能超界。
能够正确使用共享内存的方式来完成进程间的数据通讯,我们则可以完成健壮的应用系统,当然你也可以使用消息队列或更高层次的进程通讯方法(IPC),甚至可以采用网络的方式来进行数据交换,在这里我们不做详细讨论。
参考文献:
[1] Beveridge J,Wiener R. Multithreading Applications in Win32[M].Addison-wesley Professional,2002.
[2]魏亮,,李春葆.Visual C++程序设计例学与实践[M].北京:清华大学出版社,2000.