thread问题(高手来温习一下,菜鸟来学习一下!)(100分)

  • 主题发起人 主题发起人 铁盒子
  • 开始时间 开始时间

铁盒子

Unregistered / Unconfirmed
GUEST, unregistred user!
TThreadDM = class(TThread)
constructor Create(CreateSuspended: Boolean);
procedure Execute;
Override;
end;
constructor TThreadDM.Create(CreateSuspended: Boolean);
begin
Create(CreateSuspended);
FreeOnTerminate := False;
end;

procedure TThreadDM.Execute;
begin
Dm.Connect;
Terminate;

end;
//DM是全局变量,从TObject继承下来的,用到了TClientDataSetConnect,connect连接到数据库
主程序
var
frmMain: TfrmMain;
thDM: TThreadDM;
begin
Application.Initialize;
DM := TDM.Create;
thDM := TThreadDm.Create(True);
thDM.Resume;
LoginInput(Application.Handle, DM.User);//输入用户名和密码
thDm.WaitFor;
DM.Login;
....
end
意思就是在用户输入密码时在另一个线程中连接数据库,加快启动速度 。现在TThreadDM.Execute中如果Synchronize(DM.Connect),则要到线程执行完,才能正常输入用户名和密码,如果不用Synchronize则不能正常连接数据库!
怎样才能另一线程连接数据库时,主线程正常输入?
 
没有必要,如果你通过验证了,但其它的窗口中的Connection联不上,那你通过验证又有什么用呢, 最后还是报个数据联接的错。
如果你线程连都连不上你主线程的肯定也连不上,不也是要退出。
 
DM在主線程里,並且DM有一些event會在主線程,所以,你的多線程方式就跟沒有一樣.白干.
你可以用ADO連接的異步執行來達到目的
 
这点速度就不用争取了。
你看看sql server 的 query analyzer。它不也是先输入用户名,然后再连接的吗?
你这样做,不觉得有什么新意。
 
to lb_icesea79:所有窗体公用一个连接
to HuiYue:为了加快其他DLL,Exe的启动速度,在单独的Exe中连接数据库, 通过Com交换数据,所以第一次连接时,要打开两个Exe,很慢,所以要争取这些时间。DM内部通过COM和连接数据的Exe交换数据。
to foresail:改为在主线程中连接数据库,新建一个线程进行用户输入,是否可以?
 
可以变通一下用一个全局变量标志数据库连接有无完成
完成了,在你的连接线程中给全局标志赋真值
然后那个登录的界面自己做,只要控制住确定按钮可不可用就能避免数据库还没连接完全用
户就已经登录了
在主程序中
当登录窗口show以后
while not 全局标志do
begin
登录按钮可用;
application.ProcessMessages;<<让用户名和密码还有机会输入
end;
 
逻辑错误!!!
while not 全局标志do
begin
application.ProcessMessages;<<让用户名和密码还有机会输入
end;
登录按钮可用;
 
to 52Free:把输入截面放在线程中好不好使!
 
一般我的做法,输入截面CREATE的时候建立与后台的连接。
输入用户名的时候就找到这个用户,
输入密码的时候就比较找到的这个密码是否正确,就这样。
没有必要用线程。
 
是不是Dm不能这么创建啊?
改成Application.CreateForm(DM,TDM)试试;
我是菜鸟,进来学习的。^_^
 
你用两 个线程,你怎么让另一个线程明白,主线程是让它继续还是停止啊
 
不管铁盒子的架构如何,他的目的、思路都是很好的。等候用户输入用户名和密码过程中CPU比较空闲,刚好用来执行数据库连接。
如果ClientDataset是线程安全的,当然很好,在线程中执行它。问题是:它真的线程安全吗?如果不是线程安全你只能用Synchronize来执行,然而,Synchronize执行的过程却是在主线程中的,你的图谋并不能得逞。所以你的问题只是如何保证ClientDataset线程安全。否则你无法放到线程中。
一招不行,又换一招。将登录代码放到线程中?那么你用什么方式启动它?Show?ShowModal?如果你用Show,所有输入输出的消息都是从主线程走的,你的线程没有意义。如果用ShowModel,你截获了Application的消息循环,更糟糕。
我的建议:建立一个登录框的Dialog资源,在线程中建立一个Parent为Application.Handle的顶层窗口,然后建立线程内的消息循环。进入循环前以Modal方式启动这个对话框,在对话框的消息过程中控制线程是否结束。在主线程中执行ClientDataset的连接,连接成功后,线程如果未执行完毕则等候线程执行完。如果连接失败则通过消息终止线程、关闭对话框。
 
to Carlsberg:
谢谢Carlsberg!你的方法对我来说,难度较大。系统结构是这样的:
-----------------------------------------------------------
A.exe
实现了Com接口IComQuery,负责连接数据库,读取数据,保存数据
-----------------------------------------------------------
B.exe
定义了
TDM=Class(TObject)
CQ:IComQuery;
Data:TClientDataSet;
.....
procedure Connect;
end;
TDM封装CQ,Connect时初始化CQ,因为IComQuery在A.Exe中,第一次速度很慢。
----------------------------------------------------------------------
把CQ设为全局变量在Thread中连接是否可以?有没有简便的方法!

 
关键看你初始化CQ的代码是否线程安全了。看起来好象无啥大问题。你可以试试在线程中运行TDM的Connect方法,结束后用某种方式给应用程序通知连接结果。例如:
type
TDMState = (dsConnecting, dsConnected, dsFailed);
var
DMState: TDMState = dsConnecting;
procedure TThread.Execute;
begin
FreeOnTerminate := True;
DMState := dsConnecting;
DM.Connect;
if Data.Active then
DMState := dsConnected
else
DMState := dsFailed;
end;

然后写一个登录函数:
function ExecuteLogin(var LoginName, LoginPassword: string): Boolean;
var
ThHandle: THandle;
begin
with TLoginForm.Create(Application)do
try
with TDMThread.Create(False)do
ThHandle := Handle;
Result := ShowModel = mrOK;
if Result then
begin
if DMState = dsConnecting then
//线程还没有结束
WaitForSingleObject(ThHandle, 30000);
//假定超时值为30秒
case DMState of
dsConnecting:
begin
Result := False;
... 终止线程
end;
dsConnected:
begin
LoginName := Edit1.Text;
LoginPassword := Edit2.Text;
end;
dsFailed:
Result := False;
//因为连接失败而结束
end;
end;
finally
Free;
end;
end;
 
漏了一点:if Result then
else
的代码,取消登录后也应该处理。
 
to Carlsberg:
procedure DM.connect;
begin
CQ:=CoComQuery.Create;
end
procedure DM.connected;
begin
CQ:=CoComQuery.Create;
end
procedure TThreadDm.Execute
begin
FreeOnTerminate := True;
DMState := dsConnecting;
DM.Connect;
if dm.Connected then
DMState := dsConnected
else
DMState := dsFailed;
end;
CoComQuery是Com类
按你的方法试了一下,在Delphi中调试时执行CoComQuery.Create出现‘标记没有引用’异常.在window中能够运行时,没有错误。我原来用TThread.WaitFor代替WaitForSingleObject也是出这个异常,但不能运行。
 
接受答案了.
 
后退
顶部