帖子http://expert.csdn.net/Expert/topic/1492/1492778.xml解决了用线程查询的问题,但是新问题又来了,用什么方法中断正在查询的线程呢?
用Terminate方法是不行的,他仅仅设置了一个标志,如果直接delete查询的线程,也不行,报“Systemc Error:code 5 拒绝访问”错。
希望各位能探讨一下。
用Terminate方法是不行的,他仅仅设置了一个标志,如果直接delete查询的线程,也不行,报“Systemc Error:code 5 拒绝访问”错。
希望各位能探讨一下。
http://www.delphibbs.com/delphibbs/dispq.asp?lid=1076676SQL运行中,你不可能去中断它,不过也没试过异步方式线程的中止,如果你作了线程的循环处理的话应该比较简单,但SQL命令就
Progress, MaxProgress: Integer; var EventStatus: TEventStatus);
beginend;你是说将EventStatus变成esCancel就行了???我以前试过,因为数据量比较大,试了一下做成异步,但后来发现Progess, MaxProgress都不太正确,而且好像那么对应的事件也不太确定,就弃之了。
我的程序框架是两个线程,主线程是界面,查询线程负责查询,查询完成后通过同步后在主界面显示结果。但是查询线程无法即时终止查询操作。
TClientDataSet的RemoteServer执行命令时,如果命令没返回,那不可能中止的线程的中止只是在循环中没有阻塞的情况下进行的,如果阻塞了俺不知道。
---------------------------------------
unit Unit1;interfaceuses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls,UThTest, DB, ADODB;type
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
Label1: TLabel;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure a(Sender : TObject) ;
private
{ Private declarations }
public
{ Public declarations }
end;var
Form1: TForm1;
tt : TTest ;
b : Boolean = True ;implementation
{$R *.dfm}procedure TForm1.a(Sender : TObject) ;
begin
Caption := 'End Of The Thread In Gear ' ;
end ;procedure TForm1.Button1Click(Sender: TObject);
begin
Caption := 'Form1' ;
tt := TTest.Create(False);
tt.OnTerminate := a ;
end;procedure TForm1.Button2Click(Sender: TObject);
begin
b := False ;
TerminateThread(TTest(tt).Handle,0);
TTest(tt).Free ;
Caption := 'end ' ;
end;end.TThread :
--------------
unit UThTest;interfaceuses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, DB, ADODB ;type
TTest = class(TThread)
private
{ Private declarations }
procedure p ;
protected
procedure Execute; override;
end;implementation{ Important: Methods and properties of objects in VCL or CLX can only be used
in a method called using Synchronize, for example, Synchronize(UpdateCaption); and UpdateCaption could look like, procedure TTest.UpdateCaption;
begin
Form1.Caption := 'Updated in a thread';
end; }{ TTest }uses Unit1 ;procedure TTest.Execute;
begin
{ Place thread code here }
Synchronize(p) ;
end;procedure TTest.p ;
var
ADOQuery1 : TADOQuery ;
begin
ADOQuery1 := TADOQuery.Create(Nil) ;
with ADOQuery1 do
begin
ConnectionString := 'Provider=SQLOLEDB.1;Persist Security Info=False;User ID=sa;Initial Catalog=hdcims;Data Source=FRESHMAN ' ;
Sql.Text := 'select * from zhang_cpkkc' ;
Open ;
First ;
while Not Eof do
begin
if b then
begin
Application.ProcessMessages ;
Sleep(100) ;
Form1.Label1.Caption := FieldByName('cpkkc_jxname').AsString ;
Next ;
end
Else
begin
Exit ;
end ;
end ;
end ;
end ;end.
Client Connect->SendCommand("select...") ==> DCOM ==> Server invoke COM Obj interface ==>
run & waitfor SQL("select...") ==> Reponse client在中间那层run & waitfor SQL中,你就是应该使用异步来做,不过MIDAS技术根本不是这样做的,好像就没有这个支持,或许我没试过
TThread.Execute中不要使用Synchronize进行主要的线程工作,因为它是将Synchronize中的(Method: TMethod)提交给主线程去做,所以这样,多线程就没有用了,而且如果是在线程中使用ADO or COM组件,应该配合使用CoInitialize & CoUnInitialize,真是该打你PP。。
TerminateThread这个嘛,那个嘛,俺是没用过,也不知会有什么结果,因为我就不会去用它,所以就不去研究了:D:D:D
像你那个,将那变量去了。procedure TForm1.a(Sender : TObject) ;
begin
Caption := 'End Of The Thread In Gear ' ;
tt := nil;
end ;还有将tt 放在TForm1的private区域。
procedure TForm1.Button1Click(Sender: TObject);
begin
if Assigned(tt) then Exit;
Caption := 'Form1' ;
tt := TTest.Create(False);
tt.OnTerminate := a ;
end;procedure TForm1.Button2Click(Sender: TObject);
begin
if not Assigned(tt) then Exit;
TerminateThread(TTest(tt).Handle,0);
TTest(tt).Free;
Caption := 'end ' ;
end;
ADOQuery->SQL........;
ADOQuery->Open(); // 他会立即结束,不会等到查询完毕;
// 循环等待,你可以干别的事儿,比如Application->ProcessMessages();
while (ADOConnection->State = stExecuting || ADOConnection->State = stFetching)
{
....
Application->ProcessMessages();
}
// 查询完毕或者可能被中止了
......
你可以弄一个按钮,写上[中止]
if (ADOConnection->State= stExecuting )
ADOConnection->Cancel();代码我手写的,供你参考,不一定能通过bcb,但是意思是这样的。
(用回调)觉得这样简单点吧。主线程和次线程的通讯方法比较多,用消息,事件最好不要线程中直接调用主线程的东东吧
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, DB, ADODB,ActiveX ;type
TTest = class(TThread)
private
{ Private declarations }
s : String ;
procedure p ;
protected
procedure Execute; override;
end;implementation{ Important: Methods and properties of objects in VCL or CLX can only be used
in a method called using Synchronize, for example, Synchronize(UpdateCaption); and UpdateCaption could look like, procedure TTest.UpdateCaption;
begin
Form1.Caption := 'Updated in a thread';
end; }{ TTest }uses Unit1 ;procedure TTest.Execute;
var
ADOQuery1 : TADOQuery ;
begin
{ Place thread code here }
CoInitialize(Nil) ;
ADOQuery1 := TADOQuery.Create(Nil) ;
with ADOQuery1 do
begin
ConnectionString := 'Provider=SQLOLEDB.1;Persist Security Info=False;User ID=sa;Initial Catalog=hdcims;Data Source=FRESHMAN ' ;
Sql.Text := 'select * from zhang_cpkkc' ;
Open ;
First ;
while Not Eof do
begin
if b then
begin
Application.ProcessMessages ;
Sleep(100) ;
s := FieldByName('cpkkc_jxname').AsString ;
Synchronize(p) ; // 这儿这个同步大哥改改:) ,我 Lock 不来了:)
Next ;
end
Else
begin
Exit ;
end ;
end ;
end ;
CoUninitialize ;
ADOQuery1.Free ;
end;procedure TTest.p ;
begin
Form1.Label1.Caption := s ;
end ;{ for i := 0 to 100 do
begin
if b then
begin
Application.ProcessMessages ;
Sleep(100) ;
Form1.Label1.Caption := IntToStr(i) ;
end
Else
Begin
Exit ;
end ;
end ; }end.
begin
Application.ProcessMessages ;
Sleep(100) ;
s := FieldByName('cpkkc_jxname').AsString ;
SendMessage(Form1.Handle, WM_SETTEXT, 0, Integer(PChar(S)));
Next;
end;最简单的就是消息了。消息是同步的,所以不用考虑它是否会线程冲突ADOQuery1.Free ;
CoUninitialize ;将Free放在Uninitialize之前。
我目前也是这样处理的(置线程某个变量为False),但是取消后如果要再进行查询操作,会失败,除非这个线程执行完刚才的查询语句。这才是问题所在啊。to wjlsmail(计算机质子) :
用Windows API TerminateThread()会产生资源泄漏。vcl的Thread中有一个FTerminated变量,它的Terminate方法就是简单地设置FTerminated为True,并不能即时终止线程。另外一个问题,好像各位都忽略了,即查询线程中的TDataSet对象不能在其他的线程中使用,因为会产生(无效的接口?我忘了)的错误,在移动数据库光标到一定位置后。
能简单说说3层的异步处理吗?
你到http://expert.csdn.net/Expert/TopicView1.asp?id=1511931跟一下,100分相送。
Server:
//客户发SQL命令过来,开始异步执行。
BeginQueryData(const SQLCommand: WideString);
//命令发过来后,客户不断的调用ReadQueryData,将已经取得的数据放到Data中。
//Data可以是自己的格式,或什么什么数据类型。
ReadQueryData(var Data: OleVariant);
//取消操作。
CancelQueryData;
//完成操作
EndQueryData;我现在也搞不通ReadQueryData怎么取得DataSet.Open后,已经填充了多少数据,或者它里面的数据是否填充到DataSet中了没?今天可能要进行申请XXX没心情试了
俺对MIDAS理解有限,从来没怎么做过东西
一、不要用API去终止线程,它是会造成MEMORY LEAK的,因为它不会同时FREE线程对象。
二、最好不要用全局变量或成员变量来进行线程间通信,否则在多CPU在机器上跑你就会死得很难看,要用Event/Mutex/Semaphore等才可靠。
三、在三层的客户端即使终止了客户端的查询也没有用,中间层仍在占用资源进行查询,而且如果强行终止客户端线程还可能会导致中间层出错,或scktsrvr等代理程序出错。
TThreadStatus = (tsIdle, tsBusy);TMyThread = class(TThread)
private
FStatus: TThreadStatus;
public
property Status: TThreadStatus read FStatus;
end;procedure TMyThread.Execute;
var
msg: TMsg;
begin
FStatus := tsIdle;
while not Terminated do
if GetMessage(msg, 0, 0, 0) do
begin
FStatus := tsBusy;
case msg.message of
...//to you code...
end;
// 处理完成,做回调,再将FStatus置闲
FStatus := tsIdle;
end;
end;然后主线程起动一个线程或多个线程,查Status是否Idle,不然就将任务给那个线程。然后,然后就不管它了你的是不是这个意思?
我的确是这个意思,但是我想能够取消服务器端正在进行的查询操作,因为我注意到,如果正在查询而结束进程(没有发现出错提示),我发现服务器端的查询自动终止了,我要的就是这个效果。
看样子是分流了!
看看,祖国大地一片红!
我这个一颗星星也来附庸风雅一下!
: )
能否给个小的示例
private
FMyEvent : TEvent;
// other info
public
property MyEvent: TEvent read FMyEvent;
// other info/methods
end;procedure TMyThread.Execute;
begin
While Not Terminated Do
Begin
If ( FMyEvent.WaitFor( $FFFFFFFF ) = wrSinaled ) Then // 线程会在这里挂起,不占用资源,直到MyEvent被Set
// do something
Else
Terminate;
End;
End;
MainForm:
...
// Set info
MyThread.MyEvent.Set;
MyThread.MyEvent.Reset;
// 上两句等效于Pulse一下,然后线程就开始一次查询,查完线程就挂住了
end;
谢谢,试试先……
否则:
三、在三层的客户端即使终止了客户端的查询也没有用,中间层仍在占用资源进行查询,而且如果强行终止客户端线程还可能会导致中间层出错,或scktsrvr等代理程序出错。若真的要强行终止线程,也不要用API来做:
一、不要用API去终止线程,它是会造成MEMORY LEAK的,因为它不会同时FREE线程对象。建议做法:
不要用TThread类,用RTL的BeginThread来实现
只能不用TThread了:<
ADOStoreProc无法调用参数类型为text的存储过程
1、任何调用在进入同一个com的时候,都会进入临界区,其他线程都被阻塞,实际上是不允许他们同时进入同一个Com的。
2、ADOConnection异步调用,实际上你也不可能立刻返回,这时候也不允许其他线程进入这个Com,因为ADOConnection这时候是存在状态的,如果你立刻退出临界区,那么其他线程进入,就会破坏你先前的调用。这样使用异步调用毫无意义。最好的解决办法,就是用多个SocketConnection。