DCOM配置方法及DCOM并行计算程序的构建

发布时间:2011-01-04 20:41:04

感谢焦龙同学的耐心讲解~~~~

1. 如何搭建DCOM编程、运行环境

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访问将不是这个样子。

运行

2. 如何新建立一个DCOM工程。

Parallel Mesh Search=PMS,原地盖高楼。

之前那些事对于例子程序的调通,下面是如何新建立一个DCOM工程。

DCOM工程大概分为3个子工程:Server端、代理DLLClient端。这3部分分别要建立3个工程

2.1 建立Server

先建立一个空白的工作区

再新建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 建立代理/存根DLL

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

2.3 建立客户程序

新建一个工程

PMS_Client.cpp中的#include "stdafx.h"删了它就可以了。。。否则有出不尽的编译、链接错误。

客户端PMS_Client工程必须包含PMS.hPMS_i.c文件。方法上面都说过了。

注意:在客户端,无论编写debug还是release程序,project\setting\ c/c++中的code generation下的Use run-time library应选DEBUG Multithreaded DLL。下图所示:

3. 代码填充

3.1 PMS_Client.cpp的框架

可能用到的头文件

#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);

3.2 通信部分

红色的字为个性化信息,表示使用模板后需要根据自己工程的命名、函数调用改动的地方

//绿色的字,你懂的,不解释。。。

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);

3.3 多线程

在做并行计算的时候,需要几台处理机同时完成多个任务,这时,Client程序要建立N个线程,这N个线程将与N个处理机进行通信,将划分好的任务传给它们。每一个线程,都执行DWORD WINAPI run(LPVOID pRange)函数,在这个函数里面建立与处理机的链接,并且调用远程处理机上的接口函数,将任务传过去。等远程处理机做好以后,从[out]参数又传回数据。最后,ClientN个线程的传回数据加以处理。

全局变量

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] );

}

}

//这里设置终止时间点,用于计算加速比

4. 服务器端的任务再下发

很多情况下,我们用Client端建立线程与Server进行通信,Server又会创建线程再向Server进行通信。这也就是我们常说的处理机之间的通信。iServer处理机不可以创建线程调用自身,即ij and ik

我们打开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了,否则会出错的。

切记:ij and ik

5. 常见的链接错误及处理方法

如果按照前几章的方法进行的话,很可能到不了这一章的错误。如果出现如下错误,恭喜你,你进入《盗梦空间》里的混沌状态了。。。

如果出现此连接错误:

nafxcwd.lib(appcore.obj) : error LNK2001: unresolved external symbol ___argv
nafxcwd.lib(appcore.obj) : error LNK2001: unresolved external symbol ___argc
nafxcwd.lib(timecore.obj) : error LNK2001: unresolved external symbol __mbctype
nafxcwd.lib(apphelp.obj) : error LNK2001: unresolved external symbol __mbctype
nafxcwd.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

DCOM配置方法及DCOM并行计算程序的构建

相关推荐