每睡一秒,线程即向外面引发一次事件,我们的类可以这样
设计:
TSecondEvent = procedure (Second: Integer) of object;
TMyThread = class(TThread)
private
FSecond: Integer;
FSecondEvent: TSecondEvent;
procedure CallSecondEvent;
protected
procedure Execute; override;
public
property SencondEvent: TSecondEvent read FSecondEvent
write FSecondEvent;
end;
{ TMyThread }
procedure TMyThread.CallSecondEvent;
begin
if Assigned(FSecondEvent) then
FSecondEvent(FSecond);
end;
procedure TMyThread.Execute;
var
i: Integer;
begin
for i := 0 to 9 do
if not Terminated then
begin
Sleep(1000);
FSecond := i;
Synchronize(CallSecondEvent);
end
else
Break;
end;
在主窗体中假设我们这样操作线程:
procedure TForm1.Button1Click(Sender: TObject);
begin
MyThread := TMyThread.Create(true);
MyThread.OnTerminate := ThreadTerminate;
MyThread.SencondEvent := SecondEvent;
MyThread.Resume;
end;
procedure TForm1.ThreadTerminate(Sender: TObject);
begin
ShowMessage('ok');
end;
procedure TForm1.SecondEvent(Second: Integer);
begin
Edit1.Text := IntToStr(Second);
end;
我们将每隔一秒就得到一次通知并在Edit中显示出来。
现在我们已经知道如何正确使用Execute方法,以及如何在主线程与工作线程之间
通信了。但
问题还没有结束,有一种情况出乎我的意料之外,即如果 线程中有一些资源,Execute正在使用这些资源,而主线程要释放这个线程,这个线程在释放的过程中会释放掉资源。想想会不会有问题呢,两个线程,一个 在使用资源,一个在释放资源,会出现什么情况呢,
用下面代码来说明:
type
TMyClass = class
private
FSecond: Integer;
public
procedure SleepOneSecond;
end;
TMyThread = class(TThrea
d)
private
FMyClass: TMyClass;
protected
procedure Execute; override;
public
constructor MyCreate(CreateSuspended: Boolean);
destructor Destroy; override;
end;
implementation
{ TMyThread }
constructor TMyThread.MyCreate(CreateSuspended: Boolean);
begin
inherited Create(CreateSuspended);
FMyClass := TMyClass.Create;
end;
destructor TMyThread.Destroy;
begin
FMyClass.Free;
FMyClass := nil;
inherited;
end;
procedure TMyThread.Execute;
var
i: Integer;
begin
for i := 0 to 9 do
FMyClass.SleepOneSecond;
end;
{ TMyClass }
procedure TMyClass.SleepOneSecond;
begin
FSecond := 0;
Sleep(1000);
end;
end.
用下面的代码来调用上面的类:
procedure TForm1.Button1Click(Sender: TObject);
begin
MyThread := TMyThread.MyCreate(true);
MyThread.OnTerminate := ThreadTerminate;
MyThread.Resume;
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
MyThread.Free;
end;
先点击Button1创建一个线程,再点击Button2释放该类,出现什么情况呢,违法访问,是的,MyThread.Free时,MyClass被释放掉了
FMyClass.Free;
FMyClass := nil;
而此时Execute却还在执行,并且调用MyClass的方法,当然就出现违法访问。对于这种情况,有什么办法来防止呢,我想到一种方法,即在线程类中使用一个成员,假设为FFinished,在Execute方法中有如下的形式:
FFinished := False;
try
//... ...
finally
FFinished := True;
End;
接着在线程类的Destroy中有如下形式:
While not FFinished do
Sleep(100);
MyClass.Free;
这样便能保证MyClass能被正确释放。
线程是一种很有用的技术。但使用不当,常使人头痛。在CSDN论坛上看到一些人问,我的窗口在线程中调用为什么出错,主线程怎么向其他线程发送消息等等,其实,我们在抱怨线程难用时,也要想想我们使用的方法对不对,只要遵循