DCOM配置方法及DCOM并行计算程序的构建
发布时间:2011-01-04 20:41:04
发布时间:2011-01-04 20:41:04
感谢焦龙同学的耐心讲解~~~~
N台机器的用户名和密码必须相同。最好是用Administrator
进入VC++6.0,打开HelloDcom.dsw,组建工具栏调出来。
程序全编译一遍
Server -> 组建->全部组建
PSAddSub -> 工具-> Register Control
至此配置完成
看两台机器是否可以进行DCOM访问:
网上邻居:
看访问125.223.8.122是否成功,进入工作组,输入如下:
出现如下就证明可以进行通信了。
本机IP = 125.223.8.113。测试的时候这里添加自己的IP号就行。如果想连接对方(125.223.8.122),就填对方的IP号即可。这只是一个例子,测试程序而已。以后讲到的IP访问将不是这个样子。
运行
Parallel Mesh Search=PMS,原地盖高楼。
之前那些事对于例子程序的调通,下面是如何新建立一个DCOM工程。
DCOM工程大概分为3个子工程:Server端、代理DLL、Client端。这3部分分别要建立3个工程。
先建立一个空白的工作区
再新建Server端工程PMS
组件接口函数的定义
HRESULT Para_MeshSearch( [in] long length,
[in,size_is(length)] long* raw_,
[out,size_is(length)] long* back_ );
组件接口函数的声明
在public:里面加入一句话STDMETHOD(Para_MeshSearch)( long length, long* raw_, long* back_);
组件接口函数的实现
向此文件中添加:
STDMETHODIMP CPMSCom::Para_MeshSearch(long length, long* raw, long* out)
{
//函数功能
return NOERROR;
}
注意,在编写PMSCom.cpp也就是Server端代码的时候,接口函数中数组raw是一个long*类型,在接口函数中不用重新给这个raw分配空间。因为调用这个函数的时候实参是一个具体数组。
组件注册:一般地,编译完成服务器自动注册
选中PMSCom.cpp,再编译!
这2.2节都是在PSPMS工程中的操作。再新建一个工程PSPMS
向PSPMS.def中添加如下内容:
LIBRARY PSPMS
EXPORTS
DllGetClassObject PRIVATE
DllCanUnloadNow PRIVATE
DllRegisterServer PRIVATE
DllUnregisterServer PRIVATE
GetProxyDllInfo PRIVATE
把PMS.idl生成的如下4个文件加入到工程中。
方法如下:
在如下位置加入 ,REGISTER_PROXY_DLL, _WIN32_DCOM
在如下位置加入 rpcndr.lib rpcns4.lib rpcrt4.lib
记得rpcndr.lib前面加个空格
编译,连接
注册dll:
新建一个工程
PMS_Client.cpp中的#include "stdafx.h"删了它就可以了。。。否则有出不尽的编译、链接错误。
客户端PMS_Client工程必须包含PMS.h和PMS_i.c文件。方法上面都说过了。
注意:在客户端,无论编写debug还是release程序,project\setting\ c/c++中的code generation下的Use run-time library应选DEBUG Multithreaded DLL。下图所示:
可能用到的头文件
#include
#include
#include
#include
#include
#include
#include "../PMS/PMS.h" //这个一定用得上
#define MAX_SERVER_NUM 20 //服务器的最大个数
using namespace std;
struct PMS_Range
{
long *Trans_;
long *Back_;
long length;
int pid;
};
定义struct PMS_Range,这个东东任务分配用的。变量一般要定义为结构体数组,目的是传给好几个处理机,每一个结构体数组元素就是一个处理机的任务。添加到多线程调用的参数中,跟多线程一起传到处理机那边。
struct PQS_Time
{
time_t start;
time_t end;
};
PQS_Time ptime; //处理机共同的时间,总体的时间
全局变量:
int ser_num; //用户设定服务器个数
long element_num; //数据量,数量级,保证很大的
HANDLE PMS_ThreadM[MAX_SERVER_NUM]; //客户端线程,保证每个线程对应一个服务器
char Processor[MAX_SERVER_NUM][15]; //服务器IP地址
PMS_Range range[MAX_SERVER_NUM]; //任务划分范围
从servername.txt中读取IP地址列表。文件里面每一行是一个IP地址。
void ReadProcessorList()
{
int i;
ifstream infile("servername.txt", ios::in);
for(i=0;i
infile>>Processor[i];
infile.close();
}
多线程运行函数。一个线程运行一个这样的run函数。
DWORD WINAPI run(LPVOID pRange)
{
PMS_Range* myrange = (PMS_Range*)pRange;
//通信部分
return 0;
}
ptime.start=GetTickCount(); //开始计算时间
ptime.end=GetTickCount(); //停止计算时间
printf("\n本次运算使用了%d台处理机,运行时间为:%dms\n", ser_num, ptime.end-ptime.start);
红色的字为个性化信息,表示使用模板后需要根据自己工程的命名、函数调用改动的地方
//绿色的字,你懂的,不解释。。。
HRESULT hResult;
hResult = CoInitialize(NULL); //初始化COM库
if (FAILED(hResult))
{
return 0;
}
IClassFactory *pClf;
IUnknown *pIUnknown;
wchar_t ip[42] ; //放弃使用CString类型,用wchar_t好
int len = strlen(Processor[myrange->pid]);
mbstowcs(ip, Processor[myrange->pid], len); //转换单字符串为宽字符串
ip[len] = 0 ; //设置字符串结尾
COSERVERINFO ServerInfo = { 0, ip, NULL, 0 }; //获取服务器信息
hResult=CoGetClassObject( CLSID_PMSCom,
CLSCTX_SERVER,
&ServerInfo,
IID_IClassFactory,
(void**)&pClf); //创建类厂
printf("\n线程%d正在连接服务器%s",myrange->pid,Processor[myrange->pid]);
if (FAILED(hResult))
{
printf("\n连接服务器%s失败",Processor[myrange->pid]);
return 0;
}
hResult = pClf->CreateInstance( NULL,
IID_IUnknown,
(void**) &pIUnknown); //创建组件对象
if (FAILED(hResult))
{
printf("\n创建组件对象失败[%d]",myrange->pid);
pClf->Release();
return 0;
}
pClf->Release(); //释放类厂
IPMSCom *pIMeshSearch;
hResult = pIUnknown->QueryInterface(IID_IPMSCom, (void**) &pIMeshSearch);//查询接口
if (FAILED(hResult))
{
pIUnknown->Release();
return 0;
}
//调用接口函数
pIMeshSearch->Para_MeshSearch( myrange->length,
myrange->Trans_,
myrange->Back_ );
pIMeshSearch->Release();
pIUnknown->Release();
pIUnknown = NULL;
CoUninitialize(); //释放COM库
printf("\n线程[%d]结束.",myrange->pid);
在做并行计算的时候,需要几台处理机同时完成多个任务,这时,Client程序要建立N个线程,这N个线程将与N个处理机进行通信,将划分好的任务传给它们。每一个线程,都执行DWORD WINAPI run(LPVOID pRange)函数,在这个函数里面建立与处理机的链接,并且调用远程处理机上的接口函数,将任务传过去。等远程处理机做好以后,从[out]参数又传回数据。最后,Client将N个线程的传回数据加以处理。
全局变量
HANDLE PMS_ThreadM[MAX_SERVER_NUM]; //客户端线程,保证每个线程对应一个服务器
线程函数
DWORD WINAPI run(LPVOID pRange)
{
….
//这个函数里面写通信的部分,3.2节彩色的部分那段。
}
主函数里面调用这段:
//这里设置起始时间点,用于计算加速比
for(i=0;i
{
PQS_Thread[i]=CreateThread(0, 0, call, (LPVOID)&range[i], 0, NULL); //这里是建立线程
//range[i]是对应线程i的任务。将任务i分配给线程i
}
unsigned long w1 = WaitForMultipleObjects(ser_num, PQS_Thread, TRUE, INFINITE);//监听,回收线程
//结束进程
if ( w1 == WAIT_OBJECT_0 )
{
for(i=0; i
{
::CloseHandle( PQS_Thread[i] );
}
}
//这里设置终止时间点,用于计算加速比
很多情况下,我们用Client端建立线程与Server进行通信,Server又会创建线程再向Server进行通信。这也就是我们常说的处理机之间的通信。i号Server处理机不可以创建线程调用自身,即i≠j and i≠k
我们打开PMSCom.cpp。那个主要的接口函数就是Para_MeshSearch()。我们可以想象这个接口函数就是一个Main函数。在这个函数里面的适当位置加入创建线程的代码。
在那里可以定义线程函数DWORD WINAPI call(LPVOID pRange)。
注意,在Server端的PMSCom.cpp中定义的全局变量和自定义函数的名字,不可以和Client里面的一样。形式可以一样但是名字不可以相同。比如我们在PMS_Client.cpp中定义的线程函数叫DWORD WINAPI run(LPVOID pRange),我们在PMSCom.cpp里面定义的就叫DWORD WINAPI call(LPVOID pRange)。这样就OK了,否则会出错的。
切记:i≠j and i≠k
如果按照前几章的方法进行的话,很可能到不了这一章的错误。如果出现如下错误,恭喜你,你进入《盗梦空间》里的混沌状态了。。。
如果出现此连接错误:
nafxcwd.lib(appcore.obj) : error LNK2001: unresolved external symbol ___argvnafxcwd.lib(appcore.obj) : error LNK2001: unresolved external symbol ___argcnafxcwd.lib(timecore.obj) : error LNK2001: unresolved external symbol __mbctypenafxcwd.lib(apphelp.obj) : error LNK2001: unresolved external symbol __mbctypenafxcwd.lib(filelist.obj) : error LNK2001: unresolved external symbol __mbctype
按照下面的方法可以解决
链接错误mfcs42d.lib(dllmodul.obj) : error LNK2005解决方法
Project->setting->link->input->Object/Library Modules,加入“mfcs42d.lib MSVCRTD.lib”,顺序不能乱
Linking... mfcs42d.lib(dllmodul.obj) : error LNK2005: _DllMain@12 already defined in dlldata.obj 的解决方法如下:
将_USRDLL删掉
出现如下错误:
Linking...
nafxcwd.lib(afxmem.obj) : error LNK2005: "void * __cdecl operator new(unsigned int)" (??2@YAPAXI@Z) already defined in LIBCD.lib(new.obj)
nafxcwd.lib(afxmem.obj) : error LNK2005: "void __cdecl operator delete(void *)" (??3@YAXPAX@Z) already defined in LIBCD.lib(dbgdel.obj)
nafxcwd.lib(thrdcore.obj) : error LNK2001: unresolved external symbol __endthreadex
nafxcwd.lib(thrdcore.obj) : error LNK2001: unresolved external symbol __beginthreadex
Debug/PQS.exe : fatal error LNK1120: 2 unresolved externals
执行 link.exe 时出错.
Linking...
nafxcwd.lib(afxmem.obj) : error LNK2005: "void * __cdecl operator new(unsigned int)" (??2@YAPAXI@Z) already defined in LIBCMTD.lib(new.obj)
nafxcwd.lib(afxmem.obj) : error LNK2005: "void __cdecl operator delete(void *)" (??3@YAXPAX@Z) already defined in LIBCMTD.lib(dbgdel.obj)
libcd.lib(crt0dat.obj) : error LNK2005: __cinit already defined in LIBCMTD.lib(crt0dat.obj)
libcd.lib(crt0dat.obj) : error LNK2005: _exit already defined in LIBCMTD.lib(crt0dat.obj)
libcd.lib(crt0dat.obj) : error LNK2005: __exit already defined in LIBCMTD.lib(crt0dat.obj)
libcd.lib(crt0dat.obj) : error LNK2005: __cexit already defined in LIBCMTD.lib(crt0dat.obj)
libcd.lib(crt0dat.obj) : error LNK2005: __c_exit already defined in LIBCMTD.lib(crt0dat.obj)
libcd.lib(crt0dat.obj) : error LNK2005: __C_Exit_Done already defined in LIBCMTD.lib(crt0dat.obj)
libcd.lib(crt0dat.obj) : error LNK2005: __C_Termination_Done already defined in LIBCMTD.lib(crt0dat.obj)
libcd.lib(crt0dat.obj) : error LNK2005: __exitflag already defined in LIBCMTD.lib(crt0dat.obj)
libcd.lib(crt0dat.obj) : error LNK2005: __wpgmptr already defined in LIBCMTD.lib(crt0dat.obj)
libcd.lib(crt0dat.obj) : error LNK2005: __pgmptr already defined in LIBCMTD.lib(crt0dat.obj)
libcd.lib(crt0dat.obj) : error LNK2005: ___winitenv already defined in LIBCMTD.lib(crt0dat.obj)
libcd.lib(crt0dat.obj) : error LNK2005: __wenviron already defined in LIBCMTD.lib(crt0dat.obj)
libcd.lib(crt0dat.obj) : error LNK2005: ___initenv already defined in LIBCMTD.lib(crt0dat.obj)
libcd.lib(crt0dat.obj) : error LNK2005: __environ already defined in LIBCMTD.lib(crt0dat.obj)
libcd.lib(crt0dat.obj) : error LNK2005: ___wargv already defined in LIBCMTD.lib(crt0dat.obj)
libcd.lib(crt0dat.obj) : error LNK2005: ___argv already defined in LIBCMTD.lib(crt0dat.obj)
libcd.lib(crt0dat.obj) : error LNK2005: ___argc already defined in LIBCMTD.lib(crt0dat.obj)
libcd.lib(crt0dat.obj) : error LNK2005: __winminor already defined in LIBCMTD.lib(crt0dat.obj)
libcd.lib(crt0dat.obj) : error LNK2005: __winmajor already defined in LIBCMTD.lib(crt0dat.obj)
libcd.lib(crt0dat.obj) : error LNK2005: __winver already defined in LIBCMTD.lib(crt0dat.obj)
libcd.lib(crt0dat.obj) : error LNK2005: __osver already defined in LIBCMTD.lib(crt0dat.obj)
libcd.lib(crt0dat.obj) : error LNK2005: __umaskval already defined in LIBCMTD.lib(crt0dat.obj)
libcd.lib(winxfltr.obj) : error LNK2005: __XcptFilter already defined in LIBCMTD.lib(winxfltr.obj)
libcd.lib(winxfltr.obj) : error LNK2005: __XcptActTabCount already defined in LIBCMTD.lib(winxfltr.obj)
libcd.lib(winxfltr.obj) : error LNK2005: __Num_FPE already defined in LIBCMTD.lib(winxfltr.obj)
libcd.lib(winxfltr.obj) : error LNK2005: __First_FPE_Indx already defined in LIBCMTD.lib(winxfltr.obj)
libcd.lib(winxfltr.obj) : error LNK2005: __XcptActTab already defined in LIBCMTD.lib(winxfltr.obj)
LINK : warning LNK4098: defaultlib "libcd.lib" conflicts with use of other libs; use /NODEFAULTLIB:library
Debug/PQS.exe : fatal error LNK1169: one or more multiply defined symbols found
执行 link.exe 时出错.
PQS.exe - 1 error(s), 0 warning(s)
[Project] --> [Settings] --> 选择"Link"属性页,
在Project Options中将/subsystem:console改成/subsystem:windows
温馨提示:在Project Options窗口,右边滑动条向下滑动就会找到该项!
Linking... nafxcwd.lib(afxmem.obj) : error LNK2005
修改project-> setting -> General-> Mircosoft Fountation classes 为Use mfc in a shard dll