请问一个很烦也很无奈的问题,有时候clientdataset 竟然在open时就停止响应了(200分)

  • 主题发起人 主题发起人 jacob0076
  • 开始时间 开始时间
J

jacob0076

Unregistered / Unconfirmed
GUEST, unregistred user!
我的线程如下,即使把ClientDataset的open过程在进程中打开也会出现有时候在open处停止响应的问题,请大侠们指点指点吧!
unit UQueryThread;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
npublicMisc,npublicStrAndTstr,npublicFileAndDir,npublicSQLStr,npublicDBVcl,
npublicTstrSection,npublicTreeview,npublicNonDBVcl,dbclient,UShowInfo,
db,dbtables,dbgrids,UTsystbl0,UTsystbl1,UTsystbl2p1,SConnect;
type
TQueryThread = class(TThread)
private
public
Fsoc: TSocketConnection;
FCDS:TClientDataSet;
Running:boolean;
constructor Create(CDS1:TClientDataSet;soc: TSocketConnection;SQL:string);
destructor Destroy;
override;
protected
procedure Execute;override;
end;

implementation
{ TQueryThread }
constructor TQueryThread.Create(CDS1:TClientDataSet;soc: TSocketConnection;SQL:string);
begin
FreeOnTerminate:=false;

Fsoc:=TSocketConnection.Create(application);
FSoc.Address:=soc.Address;
FSoc.Host:=soc.Host;
FSoc.Port:=soc.Port;
FSoc.ServerName:=soc.ServerName;
Fsoc.ServerGUID:=soc.ServerGUID;
FCDS:=TClientDataSet.Create(application);
FCDS.RemoteServer:=Fsoc;
FCDS.CommandText:=SQL;
FCDS.PacketRecords:=CDS1.PacketRecords;
FCDS.ProviderName:=CDS1.ProviderName;
inherited Create(true);
end;

destructor TQueryThread.Destroy;
begin
FSOC.Connected:=false;
FCDS.Close;
FreeAndNil(FCDS);
FreeAndNil(FSOC);
inherited;
end;

procedure TQueryThread.Execute;
begin
Running:=true;
try
Fsoc.Connected:=true;
FCDS.Open;//有时候到这里就不继续往下做了,程序也失去响应了,要强行关闭才行
Running:=false;
finally
end;

end;

end.
 
Fsoc.Connected:=true;
FCDS.Open;//有时候到这里就不继续往下做了,程序也失去响应了,要强行关闭才行
将 Fsoc.Connected:=true; 去掉试试看,一般来说Open的时候,会自动打开连接了,先打开了再OPEN,好像是会创建新的连接,然后会导致错误。 
试试看,不知道对不对。
 
Fsoc:=TSocketConnection.Create(application);
Application对象不是线程安全的,不要在线程里面(或者线程内部创建的对象中)引用任何外部的VCL对象,VCL的框架本身就不是线程安全的。
不过这个可能和你的open时停止响应无关,我仅是指出这一点提醒您注意而已。
 
把程序中的
Fsoc:=TSocketConnection.Create(application);
改为
Fsoc:=TSocketConnection.Create(nil);
和把
Fsoc.Connected:=true;去掉还是一样啊,该怎么办呢?
 
可能是远程主机没有响应,你把FSoc指向本机试试,通过了再试远程。
 
TO nicai_wgl
在本机调试没有出现过这种错误,就是在远程调试的时候才发现这种错误,请问有什么可能会造成这种错误呢?还发现,在远程调试时(在delphi中按F9运行)未出现错误,但直接运行EXE就会不定时出现这种错误。
 
呵呵,如果F9不出错而直接运行出错,可能是网络延时,在
Fsoc.Connected:=true;
sleep(1000);
//加延时试试
FCDS.Open;//有时候到这里就不继续往下做了,程序也失去响应了,要强行关闭才行
 
能不能在调用线程时用 WaitForSingleObject(t1.Handle,10) 循环来检测是否在open处停顿呢?但好像用
WaitForSingleObject(t1.Handle,10);
或者用if WaitForSingleObject(t1.Handle,10)=WAIT_TIMEOUT then

或者用if WaitForSingleObject(t1.Handle,10)=WAIT_OBJECT_0 then

都在open时就同时停顿不能执行下去,要怎样才能检测到停顿呢?
 
现在问题变成了怎样检测长时间open不响应时,如何抛出异常信息了
 
在进程或线程中能够处理都行啊,如果分不够,还可以再加200分啊
 
可以用TSimpleEvent, 在Open之前ResetEvent, Open成功后SetEvent, 在主线程中等待,
如果超时则弹出异常, 结束子线程。
 
程序改成了下面
unit UQueryThread;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
dbclient,db,dbtables,dbgrids,SConnect,SyncObjs;
type
TQueryThread = class(TThread)
private
public
Fsoc: TSocketConnection;
FCDS:TClientDataSet;
SimpEvent:TSimpleEvent;
constructor Create(CDS1:TClientDataSet;soc: TSocketConnection;SQL:string);
destructor Destroy;
override;
protected
procedure Execute;override;
end;

implementation
{ TQueryThread }
constructor TQueryThread.Create(CDS1:TClientDataSet;soc: TSocketConnection;SQL:string);
begin
inherited Create(true);
self.FreeOnTerminate:=false;
Fsoc:=TSocketConnection.Create(nil);
FSoc.Address:=soc.Address;
FSoc.Host:=soc.Host;
FSoc.Port:=soc.Port;
FSoc.ServerName:=soc.ServerName;
Fsoc.ServerGUID:=soc.ServerGUID;
FCDS:=TClientDataSet.Create(nil);
FCDS.RemoteServer:=Fsoc;
FCDS.CommandText:=SQL;
FCDS.PacketRecords:=CDS1.PacketRecords;
FCDS.ProviderName:='tmpQryProvider';
end;

destructor TQueryThread.Destroy;
begin
FreeAndNil(SimpEvent);
FSOC.Connected:=false;
FCDS.Close;
FreeAndNil(FCDS);
FreeAndNil(FSOC);
inherited;
end;

procedure TQueryThread.Execute;
begin
try
SimpEvent:=TSimpleEvent.Create;
SimpEvent.ResetEvent;
FCDS.Active:=true;
SimpEvent.SetEvent;
finally
end;
end;

end.

然后是调用的代码:
t1:=TQueryThread.Create(cltDataSet,DCOM1,sql);
t1.resume;
while t1.SimpEvent=nildo
sleep(1);
if WaitForSingleObject(t1.SimpEvent.Handle,5000)=WAIT_TIMEOUT then
t1.Suspend;

if t1.FCDS.Active then
begin
cltdataset.Data:=t1.FCDS.Data;
result:=true;
end
else
begin
application.MessageBox('数据搜索失败','提示',0);
while t1.Suspended=falsedo
t1.Suspend;
end;

结果还是一样,如果在FCDS.Active:=true;处死掉还是不会执行t1.suspend;
这句
 
其实你没有必要在线程里面开多一个连接,还是用原来的连接吧。
具体的实现你可以看看这个帖子。
http://www.delphibbs.com/delphibbs/dispq.asp?lid=2280814
首先你应该在创建线程的时候把取数据时候需要调用的接口传递进来。
OleCheck(CoMarshalInterThreadInterfaceInStream(IID_IAppServer,FCDS.AppServer,
IStream(FStream)));
然后你在调用该接口的时候需要把它拿回来。
OleCheck(CoGetInterfaceAndReleaseStream(IStream(FStream), IID_IAppServer,
Appserver));
好了,可以调用该接口拿数据了。
FNewData :=AppServer.AS_GetRecords (FCDS.ProviderName,
-1,RecsOut,MetaDataOption,'',Params,OwnerData);
然后把数据更新回去,因为要接受数据的是一个线程外部的对象,你需要跟主线程同步
Synchronize(UpdateCDS);
这样就完成了。
 
To:kkkchenA
这种方法在我的系统不能用。
系统换了N种方法后问题好像解决了
 
多人接受答案了。
 
后退
顶部