应用服务器接口被客户端不断多次调用会出现访问异常,怪。(200分)

  • 主题发起人 主题发起人 zag2000
  • 开始时间 开始时间
Z

zag2000

Unregistered / Unconfirmed
GUEST, unregistred user!
在多个客户端不断调用同一个应用服务器的接口函数时,该接口函数有时会出现
内存访问的异常,如:Login Error: Access violation at address 004CA3EC in module 'AppServer.exe'. Read of address 00000016
不知道为什么,是Delphi的问题?如何解决?如Login接口函数:
procedure TDataService.Login(const ALoginName: WideString);
var
ListItem: TListItem;
begin
try
FLoginName := ALoginName;
ListItem := ServerMainFrm.lvLoginNameList.FindCaption(0,ALoginName,False,True,True);
if ListItem = nil then
begin
ServerMainFrm.UpdateClientCount(1);
ListItem := ServerMainFrm.lvLoginNameList.Items.Add;
ListItem.Caption := ALoginName;
ListItem.SubItems.Add('Count=1');
end
else
begin
ListItem.SubItems.Values['Count'] := IntToStr(StrToInt(ListItem.SubItems.Values['Count'])+1);
end;
except
on E: Exceptiondo
WriteLog('Time: ' + DateTimeToStr(Now) + ' Login Error: ' + E.Message);
end;
end;

 
你的代码在事实上是在一个线程里操作ServermainFrm的元素了,而事实上没有任何同步
机制,所以在多客户并发时就可能出错了。
解决很简单,在Login这个方法里用临界区就行了。如下:
进入临界区
try
....你的代码
finally
退出临界区
end;
 
to szf:
thanks.有道理。是不是在RDM里访问其他全局对象的时候都需要做临界区处理呀?
另外,我的系统中,客户端ClientDataSet的Open和ApplyUpdates方法执行时,有时侯不返回了,客户端就死机了,是不是和应用服务器有关呢?这种现象偶尔发生。
在开发应用服务器方面有什么主意的地方请略指点一二,谢谢!
 
信号灯(Semaphore)、互斥(Mutex)、临界区(CriticalSection)这几种解决并发访问的
方式有什么不同,一般在应用服务器开发中采用哪种比较合理和方便呢?
 
用synchronize吧!这是vcl的解决方案,开销要小一些
 
Synchronize只是对VCL的方法吧?对于对象的属性的访问怎么办?会不会在并发访问的时候异常?我觉得还是采用临界区比较好。
 
访问全局变量是否要做同步要看访问的机制而定,一般来说,都是读取就不必要了,如果是写,当然就要同步了。只是一般来说,具体情况具体分析。
简单来说,有以下概念:
临界区:只能进入一次,另外的线程进入时,会排队并无限等待,
所以必须通过try..finally..end方法保证退出临界区。
互斥元:只能取得一次,另一个线程可通过WaitForSingleObject来决定
自己的等待时间,如果使用Windows.pas单元的INFINITE常量作为
等待时间参数,则与一个临界区没有区别。
旗帜: 可以取得多次,次数由建立旗帜时决定,如果旗帜已用完,则可以
通过WaitForSingleObject来等待其它线程释放空闲旗帜。如果
旗标数是1,则与一个互斥元没有区别。

你说的不返回是什么意思?这个没什么好说的呀,不过如果客户跟服务器不在同一台机上,网络通讯丢包,可能也会这样吧。
 
其实,rdm本身是多线程的,你的代码不行是因为ServermainFrm不是多线程的,访问他的
控件时出现了冲突,所以用synchronize正好对路。它就是解决多线程访问vcl的问题的
 
to szf:
非常感谢你的解释。我想我的RDM中的接口函数使用临界区就可以。
我说的不返回不是指没有数据包返回,是有时侯客户端程序执行Open或ApplyUpdates时就死了,不知道为什么,也是偶尔发生,是不是跟Scktsrvr.exe有关呢?
to wfzha:
synchronize是TThread的方法,在RDM中没有呀,TRemoteDataModule从TDataModule中继承的。
 
看了获益匪浅
 
我说的就是网络丢包,引起远过程调用不返回呀,这个问题很难说,不过几乎可以肯定是网络引起的,网络的问题我就解决不了了。
 
to szf:
我也觉得应该是网络的问题,我增加对全局方法和对象的临界区控制后,修改了scktsrvr.exe的一些bug,并作了一些大强度对应用服务器的访问和网络数据存取操作,目前一直没有发生错误,运行良好。
 
你修改了哪些Scktsrvr.exe的BUG呢,可否帖上来看看?
 
多人接受答案了。
 
后退
顶部