动态库中的多线程数据存取 (这问题暂时放一下了,大家来分分吧) (200分)

  • 主题发起人 主题发起人 Sachow
  • 开始时间 开始时间
S

Sachow

Unregistered / Unconfirmed
GUEST, unregistred user!
我里这正遇到几个以前没有认真研究,现在不得不面对的问题,恳请各位帮我参研一下。

前段时间做了一个与其它系统接口的动态链接库,那边是多线程的方式调用的,当然我这边
也要支持多线程才行。这个动态链库要进行一些数据库的存取,调用些动态库的线程会很多,
而且不固定,数据库用的又是Oracle,用ADO不太好使(在EXE程序里正常,但在DLL里就不
行了,是不是初始化COM的问题?)。现在我的程序使用BDE已经基本上可以正常使用了,但
我还没有让它承受过多达100个以上线程的考验,现在我担心的是我的程序是否以正确的方式
应对了多线程的访问。
我的程序是这样的:在DLL的入口函数中,如果判断reason为DLL_PROCESS_ATTACH,就建立一
个TDatabase的实例,并连接数据库,这样,在线程访问动态库的时候就不会重复建立
TDatabase的实例及重复连接数据库,然后在reason为DLL_PROCESS_DETACH时销毁该实例。
我没有建立全局的TQuery实例,而是在导出的函数的实现中动态创建TQuery的实例,这样效
率可能会略低,但也许能帮我减轻保护全局变量的负担。我通过这样的方式来让动态创建的
TQuery绑定给TDatabase: tqr->DatabaseName = DB1->DatabaseName (虽然是C++ Builder
代码,但如果用Delphi同理)。在用到事务处理的地方,我用TCriticalSection进行了同步
保护,让一个线程在提交数据的期间,另一个线程不能再次提交,但在没有用到事务处理的
地方,比如Select数据的时候,由于我用的TQuery不是全局变量,就没有用TCriticalSection
进行保护。
我现在的顾虑就是:
1、像上面这样的做法是否可靠?
2、像这样的做法会遇到BDE的48连接限制吗(我现在手上没有参考书,否则可以把这个定义
搞得更清楚些)?程序在正式使用的时候,是会产生最多120个以上的线程迸发访问的,正常
情况可能只有10个以下的线程。
 
老兄,不是我该提醒你。
在这儿,发贴量太多。
如果没有人灌水,你的贴子一会儿就到后面去了,别人也看不见。
所以你又得不停的提前,好让更多的人看到你的贴子。

不是经常有人说up有分吗?我想你该明白喔。
所以,我也是来灌水!!!说白了是帮你提!

 
To Del520:好,感谢你的建议,我已经改正。
 
昨天我回家看了一下李维的书,说每个Session可以拥有256个客户端用户,这么说来我建立
的TDatabase实例拥有一个默认Session,应该就能服务256个客房端(在我的程序中就是256
个线程),是这样吧?

我还有一点困惑,看BDE的帮助上说要建立多线程的数据应用程序,就必须为每个线程建立
一个Session,这样做岂不是一台机只能服务48个线程了,48个线程显然是不够的,下一步就
必须用Session Pooling了,而使用Session Pooling又要把存取数据的应用服务器程序安装
在对方的机器上,这显然是有点不太好接受的。

以前我考虑过一种实施方法,就是把接口动态库做成一个只调用我的COM+组件的一个客房端,
里面不写任何业务逻辑,不用直接访问数据库,这看起来比较理想,但有两个问题:
1、对方服务器和我方服务器都是不同网段上的主域控制器,都是通过Administrator登录的,
我需要把调用我方服务器上的组件的客户端程序(DLL形式)放在对方服务器上,遇到的第
一个问题就是客户端的调用不能通过Windows的用户验证,调用会失败。听说服务器间可以
建立域信任关系,不知能不能解决此问题(没做过,不知道该怎么做)。
2、采用这种方式,如果我的服务器端组件有BUG,有可能导致客户端产生内存泄漏等问题,
由于客户端是一个DLL,要由对方服务器调用,这进一步可能会影响到对方服务器程序。

现在我觉得应该从以下方面考虑(原则是放尽量简单的东西在对方服务器上):
1、现在的处理方式是否有必要改一下?
2、有没有办法解决ADO对Oracle支持不太好的问题,从而使该程序可以改用ADO?
3、或者采用其它方法?
 
是不是我说的东西太复杂了,大家不想看?OK,我就说简单一点:
我的程序需要实现下面这个功能:做一个能可靠地支持100个以上线程调用,访问数据库的
动态连接库,除了不用COM以外(不是我不会用COM,而是不能在那个系统上用),不管用什
么方式实现都行。
 
我的意见是
在dll里面自己做一个pooling,当然不需要很复杂,只要够用就行,下面是具体想法
第一次被调用的时候就产生tdatabase,tsession,tquery三个构件,在tquery.open和
tquery.execsql的地方用critical section保护起来。用完以后这个链接不释放,当下个
调用来了以后就把现在找个空闲的链接给他用。当然如果请求很频繁的话也需要起别的
链接,这个可以在调用的时候遍历一下所有链接的list,如果有空闲的就用,没有空闲的
就另外生成一个。
我这个思路已经用vcl模式实现了,效果还可以
但是不知道放在dll里面能不能行
 
我看了一个Delphi的例程和李维的书上说的,好像建立Session Pooling都是要基于无状态
对象的,而且都是基于COM/DCOM技术的,但我考虑到尽量不到在对象的服务器上放置太多
的东西,因此要避免采用COM技术来处理。
看了叶孤城的思路,我觉得应该采用I/O Select的方法处理,即在动态库每次被线程调用
时,从SessionList中寻找可用的Session,如果找不到就一直循环着找,直到出现可用的
为止(或者遍历一次找不到可用的时函数就返回失败,以避免因数据库故障导致调用者的
所有线程都挂死),关键是动态创建的Session如何管理,现在我还没有主意。我现在继续
看书研究,并随时欢迎各位提出实施方案。
 
ADO就是COM,所以你不要指望用ADO了。
其他的我也不懂,你帮过我,帮你顶顶吧 ;-)
 
多人接受答案了。
 
后退
顶部