次问题困扰了我N年,如果哪位大侠帮我解决此问题小弟将满分赠送!!
---------------------------------
问题如下:我想用BDE和多线程连接Oracle(或SQLServer)数据库,因为数据库连接是很耗时的。
创建了2个多线程类,一个专门进行数据库连接、另一个专门进行连接进度显示。
结果程序一运行到FDB.Open;进行数据库连接主线程就会失去控制权,导致主线程死等现象。请高手帮忙!!!急!!!
--------以下代码Delphi5编译通过-------------------------
unit Unit2;interfaceuses
Windows, Messages, Classes, SysUtils, ComCtrls, dbTables;type
//进度线程
TProgressThread = class(TThread)
private
FDB: TDatabase;
Fpb: TProgressBar;
FConnected: boolean;
iPos: integer;
procedure DoWhatVCLAction;
public
procedure Execute; override;
constructor Create(DB: TDatabase; pb: TProgressBar);
end; //数据库连接线程
TDBConnectThread = class(TThread)
private
FDB: TDatabase;
FConnected: boolean;
FErrorStr: string;
procedure DoWhatVCLAction();
procedure DoDBConnect(out Connected: boolean; out ErrorStr: string);
public
procedure Execute; override;
constructor Create(DB: TDatabase);
property Connected: boolean read FConnected default False;
property ErrorStr: string read FErrorStr;
end;implementation{ TProgressThread }constructor TProgressThread.Create(DB: TDatabase; pb: TProgressBar);
begin
FDB:= DB;
Fpb:= pb;
FConnected:= False;
iPos:= pb.Position;
FreeOnTerminate:= true;
inherited Create(False);
end;procedure TProgressThread.DoWhatVCLAction;
begin
if not FDB.Connected then
begin
if Fpb.Position <> 100 then
Fpb.StepIt
else
Fpb.Position:= 0;
if Terminated then Fpb.Position:= 100;
end
else FConnected:= true;
end;procedure TProgressThread.Execute;
begin
while not FConnected do
begin
Inc(iPos);
synchronize(DoWhatVCLAction);
if Terminated then exit;
end;
end;{ TDBConnectThread }constructor TDBConnectThread.Create(DB: TDatabase);
begin
FDB:= DB;
FreeOnTerminate:= true;
inherited Create(False);
end;procedure TDBConnectThread.DoDBConnect(out Connected: boolean; out ErrorStr: string);
begin
Connected:= False;
try
if not FDB.Connected then
begin
FDB.Open;
Connected:= true;
end else
Connected:= true;
except
On E: Exception do ErrorStr:= E.Message;
end;
end;procedure TDBConnectThread.DoWhatVCLAction();
begin
DoDBConnect(FConnected, FErrorStr);
end;procedure TDBConnectThread.Execute;
begin
synchronize(DoWhatVCLAction);
end;end.
//----调用是这样调的:----------------
//窗体上放Database1,Table1,DataSource1,DBGrid1,Button1
//并连接字符串已经设置好了,只要用线程类进行连接即可uses Unit2;{$R *.DFM}procedure TForm1.Button1Click(Sender: TObject);
var
pro: TProgressThread;
conn: TDBConnectThread;
begin
pro:= TProgressThread.Create(Database1, Progressbar1);
conn:= TDBConnectThread.Create(Database1);end;
---------------------------------
问题如下:我想用BDE和多线程连接Oracle(或SQLServer)数据库,因为数据库连接是很耗时的。
创建了2个多线程类,一个专门进行数据库连接、另一个专门进行连接进度显示。
结果程序一运行到FDB.Open;进行数据库连接主线程就会失去控制权,导致主线程死等现象。请高手帮忙!!!急!!!
--------以下代码Delphi5编译通过-------------------------
unit Unit2;interfaceuses
Windows, Messages, Classes, SysUtils, ComCtrls, dbTables;type
//进度线程
TProgressThread = class(TThread)
private
FDB: TDatabase;
Fpb: TProgressBar;
FConnected: boolean;
iPos: integer;
procedure DoWhatVCLAction;
public
procedure Execute; override;
constructor Create(DB: TDatabase; pb: TProgressBar);
end; //数据库连接线程
TDBConnectThread = class(TThread)
private
FDB: TDatabase;
FConnected: boolean;
FErrorStr: string;
procedure DoWhatVCLAction();
procedure DoDBConnect(out Connected: boolean; out ErrorStr: string);
public
procedure Execute; override;
constructor Create(DB: TDatabase);
property Connected: boolean read FConnected default False;
property ErrorStr: string read FErrorStr;
end;implementation{ TProgressThread }constructor TProgressThread.Create(DB: TDatabase; pb: TProgressBar);
begin
FDB:= DB;
Fpb:= pb;
FConnected:= False;
iPos:= pb.Position;
FreeOnTerminate:= true;
inherited Create(False);
end;procedure TProgressThread.DoWhatVCLAction;
begin
if not FDB.Connected then
begin
if Fpb.Position <> 100 then
Fpb.StepIt
else
Fpb.Position:= 0;
if Terminated then Fpb.Position:= 100;
end
else FConnected:= true;
end;procedure TProgressThread.Execute;
begin
while not FConnected do
begin
Inc(iPos);
synchronize(DoWhatVCLAction);
if Terminated then exit;
end;
end;{ TDBConnectThread }constructor TDBConnectThread.Create(DB: TDatabase);
begin
FDB:= DB;
FreeOnTerminate:= true;
inherited Create(False);
end;procedure TDBConnectThread.DoDBConnect(out Connected: boolean; out ErrorStr: string);
begin
Connected:= False;
try
if not FDB.Connected then
begin
FDB.Open;
Connected:= true;
end else
Connected:= true;
except
On E: Exception do ErrorStr:= E.Message;
end;
end;procedure TDBConnectThread.DoWhatVCLAction();
begin
DoDBConnect(FConnected, FErrorStr);
end;procedure TDBConnectThread.Execute;
begin
synchronize(DoWhatVCLAction);
end;end.
//----调用是这样调的:----------------
//窗体上放Database1,Table1,DataSource1,DBGrid1,Button1
//并连接字符串已经设置好了,只要用线程类进行连接即可uses Unit2;{$R *.DFM}procedure TForm1.Button1Click(Sender: TObject);
var
pro: TProgressThread;
conn: TDBConnectThread;
begin
pro:= TProgressThread.Create(Database1, Progressbar1);
conn:= TDBConnectThread.Create(Database1);end;
这样线程安全吗?请高手答复!
作 者: skyclin ()
等 级:
信 誉 值: 100
所属论坛: Delphi 基础类
问题点数: 60
回复次数: 5
发表时间: 2002-11-27 17:13:05
申请说明部分:
TThreadQuery = class(TThread)
private
FQuery: TADOQuery;
LI_I:integer;
procedure GetCount;
protected
procedure Execute; override;
public
constructor Create(Query: TADOQuery;SQLString:string); virtual;
end;procedure TThreadQuery.GetCount;
begin
if FQuery.IsEmpty then
LI_I:=0
else LI_I:=FQuery.RecordCount;
end;procedure TThreadQuery.Execute;
begin
try
FQuery.Open;
Synchronize(GetCount);
except
ShowMessage('Query Error'); { 线程异常 }
end;
end;constructor TThreadQuery.Create(Query: TADOQuery; SQLString:string);
begin
inherited Create(True);
FQuery := Query;
FQuery.Connection:=JLDMFrm.DBConnection;
FQuery.SQL.Text:=SQLString;
Resume;
FreeOnTerminate := False;
end;这是调用部分:
function TheadQueryFunc(SQLString:string):integer;
var
Q1:TThreadQuery;
LQ_Q:TADOQuery;
begin
LQ_Q:=TADOQuery.create(nil);
Q1:=TThreadQuery.Create(LQ_Q,SQLString);
result:=Q1.LI_I;
Q1.Terminate; { 销毁之前终止线程执行 }
Q1.Destroy;
end;edit1.text:=inttostr(TheadQueryFunc(x));调用时edit1.text老是等于0;
为什么,为什么?
功夫不到家,望高手指点!!
回复人: zwjchina(蒲石) ( ) 信誉:100 2002-11-27 17:25:00 得分:0
好象对线程对象的属性不能这样访问,我记不清楚了,
这样,做个测试,
在result := Q1.LI_I;
前面加一句:sleep(100);
如果结果还是0,那么你还是用全局变量吧
Top
回复人: outer2000(天外流星) ( ) 信誉:100 2002-11-27 17:30:00 得分:0
function TheadQueryFunc(SQLString:string):integer;
var
Q1:TThreadQuery;
LQ_Q:TADOQuery;
begin
LQ_Q:=TADOQuery.create(nil);
Q1:=TThreadQuery.Create(LQ_Q,SQLString);
result:=Q1.LI_I;
Q1.Terminate; { 销毁之前终止线程执行 }
Q1.Destroy;
end;
你的Lq——q就没有创建啊;
回复人: wjlsmail(计算机质子) ( ) 信誉:100 2002-11-27 17:49:00 得分:0
可不可以这样改一下,由于在调用时传入的TADOQuery没有用,故:constructor TThreadQuery.Create(SQLString:string);
begin
inherited Create(True);
FQuery.Connection:=JLDMFrm.DBConnection;
//也可以将FQuery定义为主线程的全局变量,只在这儿传入Sql.Text
FQuery.SQL.Text:=SQLString;
Resume;
FreeOnTerminate := False;
end;
调用部分:
function TheadQueryFunc(SQLString:string):integer;
var
Q1:TThreadQuery;
begin
Q1:=TThreadQuery.Create(SQLString);
result:=Q1.LI_I;
Q1.Terminate; { 销毁之前终止线程执行 }
Q1.Destroy;
end;
Top
回复人: wjlsmail(计算机质子) ( ) 信誉:100 2002-11-27 18:07:00 得分:0
还有,
private
LI_I:integer;
怎么会传到外边呢? 是不是 ?
Top
回复人: wjlsmail(计算机质子) ( ) 信誉:100 2002-11-27 18:42:00 得分:0
zwjchina(蒲石) 说的是对的 我试了一下:不论怎样定义LI_I,都传出来的是 0 ,一般在同一个线程的各个线程对象间传递参数使用线程自己定义的变量 。 我改了一下:
调用:
with TThreadOfCount.Create(Edit1.Text) do
begin
if Suspended then Resume;
end;
Label1.Caption := IntToStr(II); 线程定义: TThreadOfCount = class(TThread)
private
procedure GetCount;
{ Private declarations }
protected
procedure Execute; override;
public
constructor Create(SQLString: string); virtual;
end;
var
FFQuery : TADOQuery ;
II : Integer ;implementationconstructor TThreadOfCount.Create(SQLString: string);
var
ADOC: TADOConnection;
begin
inherited Create(False);
ADOC := TADOConnection.Create(Nil);
with ADOC do
begin
ConnectionString := '...' ;
LoginPrompt := False ;
Connected := True ;
end;
FFQuery := TADOQuery.Create(Nil) ;
FFQuery.Connection := ADOC ;
FFQuery.SQL.Text := SQLString;
Resume;
FreeOnTerminate := False;
end;procedure TThreadOfCount.GetCount;
begin
if FFQuery.IsEmpty then
II := 0
else
II := FFQuery.RecordCount;
end;procedure TThreadOfCount.Execute;
begin
{ Place thread code here }
try
FFQuery.Open;
Synchronize(GetCount);
except
ShowMessage('Query Error'); { 线程异常 }
end;
end;
end.测试通过 ,但是对线程中使用参数不清楚,望大家指导
作 者: cooling (cooling)
等 级:
信 誉 值: 100
所属论坛: Delphi 网络编程/分布式开发
问题点数: 100
回复次数: 4
发表时间: 2002-11-24 15:28:02
线程大致是这样的constructor Tmythread.Create(RunStart: Boolean; p: PUDPData; FrmHandle: HWND);
begin
Handle := FrmHandle; //主线程句柄
UdpData := P; //主线程传过来的需要处理的数据指针
inherited Create(RunStart);
end;procedure Tmythread.Execute;
begin
{Place thread code here}
FreeOnTerminate := True;
while Not Terminated do
begin
//……处理数据UdpData,时间比较长
//涉及到主线程中的可视控件用了Synchronize方法同步 Suspend; //处理完后挂起,等待下次调用 end;
end;
主线程中:procedure TFrmMain.madeThread;//构造数据处理线程
var
i : Integer;
begin
setlength(RecvUDP,Thread_count-1);//创建Thread_count个数据缓冲区RecvUdp
setlength(mythread, Thread_count - 1);//创建Thread_count个数据处理线程
For i := 0 to Thread_count - 1 do//可能有很多线程
begin
new(RecvUDP[i]);
mythread[i] := Tmythread.Create(True, RecvUDP[i], FrmMain.Handle);
//一个数据处理线程对应一个数据缓冲区(创建后先挂起)
end;
end;当主线程中有数据要处理时唤醒一个线程来处理问题是我在结束程序时在主窗体的close中调用以下自定义程序FreeThread,终止线程出错:procedure TFrmMain.FreeThread;// 释放线程数组和数据缓冲数组
var
i : Integer;
begin
For i := 0 to Thread_count - 1 do
begin
mythread[i].Terminate;
mythread[i].WaitFor;//到这里时程序死了,不响应
dispose(RecvUDP[i]);
end;
end;
我也试过这么写:procedure TFrmMain.FreeThread;// 释放线程数组和数据缓冲数组
var
i : Integer;
begin
For i := 0 to Thread_count - 1 do
begin
mythread[i].suspend;
mythread[i].Terminate;
dispose(RecvUDP[i]);
end;
end;//提示错误的指针,我想是线程Terminate后还没有真正结束,但主线程中的缓冲数组已经释放掉了。
我应该怎样保证在关闭整个程序时把线程安全的释放掉??
回复人: stanely(俺是邢她汉子) ( ) 信誉:102 2002-11-24 16:25:16 得分:30
up
Top
回复人: d983074(d983074) ( ) 信誉:100 2002-11-25 15:15:21 得分:30
这是我写的线程代码
procedure tmythread.excute;
var
EventSignaled:DWORD;
EventsToWait:array [0..1] of Thandle;
begin
EventsToWait[0]:=CloseEvent;
EventsToWait[1]:=YourEvent;
while true do
begin
EventSignaled := WaitForMultipleObjects(2,@EventsToWait,False, INFINITE);
case EventSignaled of
Wait_Object_0:
begin
exit;
end;
Wait_Object_0+1:
begin
do your things;
end;
Wait_Failed:exit;
end;
end;
Top
回复人: d983074(d983074) ( ) 信誉:100 2002-11-25 15:17:13 得分:10
创建事件
closeevent:=createevent(nil,false,false,nil);
触发
setevetn(closeevent);
释放事件
closeevent(closeevent);
Top
回复人: findcsdn(findcsdn) ( ) 信誉:106 2002-11-25 18:16:33 得分:30
mythread[i].Terminate;
mythread[i].WaitFor; //到这里时程序死了,不响应上面的写法是对的,至于死的原因是因为,可能你还不了解 Terminate 过程的实质。 Terminate发放,作的唯一的事就是将线程 FTerminated:=True;
所以你在线程内要不断的检测 self.terminated 是否为真,如果为真立即跳出工作过程,退出线程,这样WaitFor才能继续执行。例如: 有一个操作数据库的线程主函数。procedure tmythread.fill;
begin
while (not dataset.Eof) and (Not terminated) do //判断terminated
begin
row:=sList.Items.Add;
row.Data:=Pointer(Data.FieldByName('fpoemid').AsInteger);
row.Caption:=data.FieldByName('ftitle').AsString;
data.Next;
end;
end;
分数也许只给答对的一个人!Help,Help!!!!!!