• 网络学院
  • 新手学堂
  • 操作系统
  • 网络技术
  • 软件应用
  • 办公软件
  • 编程技术
  • 网站架设
  • 数据库类
  • 平面设计
  • 多媒体类
  • 游戏资讯
  • 教学论文
  • 认证考试
用C++Builder建立多线程COM服务器
广告位
  站点:
  • 首 页
  • 最新软件
  • 最新文章
  • 国内软件
  • 国外软件
  • 汉化软件
  • 源码下载
  • 字体下载
用C++Builder建立多线程COM服务器
软件发布 用C++Builder建立多线程COM服务器
网络软件 系统工具 应用软件 联络聊天 图形图像 多媒体类 行业软件 游戏娱乐 编程开发 安全相关 教育教学 数码软件
热门软件: QQ 瑞星 pplive e话通 木马克星 千千静听 office2000 五笔字根 Photoshop 视频分割
返回首页 | 文章首页 | 编程技术 | BCB教程 | 用C++Builder建立多线程COM服务器

用C++Builder建立多线程COM服务器

 

添加时间: 2007-7-9 4:33:07  作者: BCB教程  阅读次数:95   来源: http://www.d9soft.com

 

 

        一、线程、Apartment和进程

说道COM的线程模型,大家就会想到各种Apartment模型。但Apartment究竟是什么?如何建立一个Apartment呢?

Apartment就是线程的容器,线程中有关COM的操作必须在Apartment中进行。Apartment分为STA和MTA两种,STA是只能容纳一个线程的容器,MTA是能容纳多个线程的容器。COM规定,一个进程中可以有多个STA,但最多只能有一个MTA。线程调用CoInitializeEx(NULL,COINIT_APARTMENTTHREADED)后,这个线程就建立并且进入了一个STA,线程调用CoInitializeEx(NULL,COINIT_MULTITHREADED)后,这个线程就进入了进程公用MTA。一个线程不能同时进入两个Apartment。线程调用CoUninitialize()后,这个线程就退出了它所在的Apartment。设计COM对象时设定的“Apartment模型”就是指这个COM对象可以呆在那种Apartment中。一个线程建立的COM对象自动地呆在这个线程所在的Apartment中。要是这个线程建立了很多个COM对象,那这些对象都呆在这个线程所在的Apartment中。

一个线程可以直接访问它所在的Apartment中的COM对象,但要访问另一个Apartment中的COM对象就必须经过调度。因为STA中只有一个线程,别的线程要访问这个线程建立的COM对象就必须让这个线程代劳了,如此一来,对这个Apartment中所有的COM对象的访问都是序列化的,这些COM对象就不用担心有好几个线程同时访问它的麻烦事。MTA中的COM对象就没这么舒服了,它们必须考虑到可能会有好几个线程同时访问它们。MTA之外的一个线程访问MTA中的一个COM对象时,系统会从COM系统线程池中取出一个线程进入MTA,由它来代表客户线程访问这个COM对象。(COM系统线程池的机理是怎么样的?池中有几个线程?)

二、客户与服务器

COM对象位于服务器中,服务器分为进程内服务器、进程外服务器、远程服务器三种。进程内服务器是一个DLL文件,进程外服务器是一个EXE文件,远程服务器是另一台计算机上的一个DLL文件或EXE文件。远程服务器如果是一个DLL文件的话,由一个被称为“Surrogate”的代理程序调用它。

进程内服务器中的COM对象的Apartment模型如果与客户线程所在的Apartment相配合的话,客户线程建立COM对象时会直接建立在客户线程所在的Apartment中。比如Apartment模型与STA、Free模型与MTA,Both模型与STA或MTA。这样客户线程就可以直接调用COM对象而不用调度。否则就会专门建立一个线程,然后由这个线程建立COM对象,COM对象和客户线程就分处在两个Apartment中。进程外服务器和远程服务器中的COM对象一定不会建立在客户线程所在的Apartment中。对它们的调用一定要经过调度的。

三、在C++Builder下建立一个多Apartment的进程外服务器

由于不必考虑并行的问题,COM对象一般设成使用Apartment线程模型。进程内服务器还没什么问题,如果你试着建了一个进程外服务器,并且让几个客户同时访问服务器中的对象的话,就会发现这些访问不是同时进行的。如果有一个访问特别费时间,它后面的访问就要等很久才能进行。这是因为服务器中只有一个STA,虽然每个线程都建立了自己的COM对象,但这些对象都在这个STA中,当然无法并行执行。

克服这个问题的办法很简单,打开Borland\CBuilder5\Include\Atl\Atlmod.h文件,把第266行的:

typedef TATLModule TComModule;

改成:

#ifdef __DLL__

typedef TATLModule TComModule;

#else

typedef TATLModule > TComModule;

#endif

再打开Borland\CBuilder5\Include\Atl\Atlcom.h文件,把第3214行的:

DECLARE_CLASSFACTORY()

改成:

#ifdef __DLL__

DECLARE_CLASSFACTORY()

#else

DECLARE_CLASSFACTORY_AUTO_THREAD()

#endif

就可以了。重新编译你的程序,同时开两个客户试一试,是不是并发执行了?

先别高兴得太早,如果你同时开了五个客户,并且其中四个在执行费时的访问,你就会发现第五个客户的访问要等待一段时间。这种现象与C++Builder的实现代码有关。

作了前面的修改后,服务器启动后会预先生成几个线程,这些线程各自进入一个STA中。当服务器接到客户的访问要求后,会循环指定一个线程负责这个客户的建立COM对象、访问COM对象的事务。

比如第一个客户要求建立一个COM对象,服务器就给一号线程发消息,让这个线程建立一个COM对象并把这个COM对象的接口传给客户,以后第一个客户对这个COM对象的访问就全由一号线程代理。而第二个客户的建立COM对象、访问COM对象的事务就由服务器指定二号线程来办,如果客户太多,线程用完了,服务器又会让一号线程负责客户的要求,依次循环。如果客户很多,线程可能会负责几个客户的访问要求,而由同一个线程服务的客户的访问就会顺序执行。预先生成的线程数缺省为系统的CPU个数乘以四,也就是四个(除非你的机器有好几个CPU)。

只能同时服务四个客户当然是不行的,让我们继续修改。打开主CPP文件,可以看到下面两行代码:

TComModule ProjectModule(0);

TComModule &_Module = ProjectModule;

改为:

TComModule ProjectModule(MyInitATLServer);

TComModule &_Module = ProjectModule;

其中“MyInitATLServer”是一个新加的函数,定义如下:

void __fastcall MyInitATLServer()

{

if (_Module.SaveInitProc)

_Module.SaveInitProc();

_Module.Init(ObjectMap, Sysinit::HInstance, NULL, 6);//注意这个6

_Module.m_ThreadID = ::GetCurrentThreadId();

_Module.m_bAutomationServer = true;

_Module.DoFileAndObjectReGIStration();

AddTerminateProc(_Module.AutomationTerminateProc);

}

看到那个6没有,这代表服务器启动后会预先生成6个线程,也就能同时服务6个客户。这个6可以改成别的数,当然不要太大了,不然机器垮了可别怪我。

改到现在你可能比较满意了,但其实这个服务器还是有缺陷:一开始就生成所有线程是不是太浪费了?循环分配线程好象也不太合理,更重要的是,如果客户程序中途垮了,没有Release它建立的COM对象,那这个COM对象将一直存在下去,占用的资源无法收回。

要解决这些问题就比较麻烦了,建议大家看一看ATL源代码,编写自己的TComModule类和CComThreadAllocator类。

四、编写多线程客户程序时要注意的问题

建立客户程序时必须包含的*_ATL.h文件中有一个很好的COM对象包装类。比如我建立了一个ComLib服务器,里面有一个MyComObj对象,那么在ComLib_ATL.h文件中有一个TCOMIMyComObj类,它很好的封装了MyComObj对象。写单线程程序时可以这样建立它:

TCOMIMyComObj aComObj = CoMyComObj::CreateInstance();

(CoMyComObj是定义在在ComLib_ATL.h文件中的一个辅助类)然后就可以使用aComObj了,不必调用CoInitializeEx()和CoUninitialize(),也不必释放aComObj。假设MyComObj对象中定义了一个方法fun(),一个属性num,可以这样使用:

aComObj.fun();

aComObj.num = 14;

int val = aComObj.num;

注意到num的访问方法了吗?C++Builder灵活运用了特有的__property关键字,不必调用get_num()和set_num()了。

如果在写多线程客户程序时也这样就会出问题:除了第一个线程正常外,后面的的线程无法建立COM对象了。

问题出在CoMyComObj里面,它保证了会调用CoInitializeEx()和CoUninitialize()并且在整个进程中只会调用一次。而在多线程客户程序中,每个线程都必须调用CoInitializeEx()和CoUninitialize()一次。因此,除了第一个线程成功进入了Apartment,别的线程都失败了。

可以这样建立TCOMIMyComObj对象:

CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);

IMyComObj *pComObj;

OleCheck(CoCreateInstance(CLSID_MyComObj, NULL, CLSCTX_LOCAL_SERVER

, IID_IMyComObj, (void **)(&pComObj)));

TCOMIComObjInExe aComObj(pComObj);

……使用aComObj……

CoUninitialize();

注意,这段代码必须写在TThread::Execute()中,因为只有TThread::Execute()里的代码才是真正运行在新线程中的。另外决不能调用pComObj->Release()。

后记

学COM的念头起于看李维写的那三本书中的第一本的时候,李维描述了建立多线程服务器的重要性,但具体方法只是一笔带过。后来我看了Delphi带的例子,想用在C++Builder中,却无从下手。在关于COM的部分,Delphi和C++Builder相差太大了,而又没有这方面的C++Builder的书,网上的资料也很少,只好自己摸索。期间曾在网上发贴提问,总是没人回答,痛苦啊!

 

 

 

上下文章:

 

上一篇文章: C++Builder定制系统菜单 下一篇文章: 用C++Builder开发动画DLL

相关文章:

  • 黑客攻破SQL服务器系统的十种方法
  • Oracle 9i服务器的关闭
  • Oracle 9i服服务器的启动
  • 安装Oracle 9i数据库服务器
  • Oracle 9i配置【管理服务器】

相关软件:

  • 北信源VRV 网络服务器端病毒库 89s
  • U-Mail V9.0 邮件服务器软件
  • InfoPath服务器 V6.6.9 B/S不限网络版
  • 遥志代理服务器(CCProxy) V6.61
  • 易捷聊天服务器 V2.0
  • java视频会议服务器 V1.0

 

 

快速导航

  • 网络学院
  • 精品汇聚
  • 字体下载
  • 教程下载
  • ASP源码
  • PHP源码
  • Net源码
  • JSP 源码

编程技术分类导航

  • ASP & ASP.NET教程
  • PHP教程
  • JSP教程
  • C/C++教程
  • VB & VB.NET教程
  • VC教程
  • Delphi教程
  • BCB教程
  • VFP教程
  • PB教程
  • JAVA教程
  • XML教程
  • C#教程
  • CGI教程

本类经典文章推荐

  • 如何在C++ Builder环境中实现在菜...
  • Windows下DLL编程技术及应用
  • 在BCB中使用DirectX
  • 用C++Builder开发动画DLL
  • 用C++Builder建立多线程COM服务器
  • C++Builder定制系统菜单
  • ODBC中的同步与异步执行模式
  • C++ Builder下数据库报表Master/D...
  • BCB环境下CORBA实做之客户端
  • 在C++Builer中多线程的实现

BCB教程阅读排行

  • C++ Builder 初学问与答(一)
  • 在 C++ Builder中利用串行通信控件...
  • C++ Builder 初学问与答(二)
  • 漫谈C++ Builder多线程编程技术
  • C++ Builder 初学问与答(十六)
  • C++ Builder 初学问与答(八)
  • 在C++ Builder中用Ole控制Excel表
  • C++ Builder 初学问与答(六)
  • C++ Builder 初学问与答(四)
  • C++ Builder 初学问与答(七)

编程技术阅读总排行

  • VB入门教程之一
  • 第二章 PowerBuilder 入门之创建新...
  • Java连接数据库实例
  • 第一章 什么是PowerBuilder
  • VC++之List Box/Check List Box控...
  • VC++ List Ctrl控件
  • VC++ Combo Box/Combo Box Ex控件
  • 学C++不得不看的一篇文章
  • VB入门教程之二
  • VC++之Button控件

广告位置

字母检索 A B C D E F G H I J K L M N O P Q R S T U V W X Y Z 回到顶部

关于我们 | 版权声明 | 免责条款 | 广告联系 | 软件发布 | 下载帮助 | 下载排行 | 网站地图 | 特别鸣谢 | 友情连接

copyright; 2005-2008 D9soft.com 第九软件网 版权所有