在用线程的时候经常要启动和挂起,原来d7的时候可以用resume和suspend(但是,建议不要用这2个方法,因为这2个方法在操作系统层面会造成死锁),现在版本的TThread里已经把这2个方法声明为deprecated(我用的是xe2,具体不知道从哪个版本起)。原来在D7的时候要挂起线程,也没用suspend,也是自己实现。
参考置顶帖(现在好象没了,只有推荐了,见 http://bbs.csdn.net/topics/360046056 ),主要是参考它的退出线程方法,写了个"通用"线程。
注:实际也不通用,我的情况是通用于主从方式的数据采集,某些系统资源,比如串口什么的,数据采集线程和主线程共用,也就是一般情况下,数据采集线程通过串口循环不断采集下位机的数据,当需要时,主线程可以挂起数据采集线程,让出资源(串口)供主线程用。
数据采集线程中,资源(串口)占用时候时间有长有短,长的时候可能数秒,主线程发出挂起命令后,采集线程不一定马上结束工作,因而要判断采集线程是否真正完成了"工作",主线程是否可以用资源(串口)了,这里就有一个等待采集线程工作完成的问题。
代码用起来虽然没发现有什么问题,不过感觉有点别扭,等待以后改进了
unit unHardWorkThread;
interface
uses
Winapi.Windows, Winapi.Messages, System.Classes, System.SysUtils, System.SyncObjs,
unGeneral;
const
WM_QUIT_HARD_THREAD = WM_USER + 301;
DELAY_TIME_MIN = 10;
type
THardWorkThread = class(TThread)
private
FQuitEvent:TEvent; //退出线程
FSuspendEvent:TEvent; //挂起线程事件,有信号表示正在工作,无信号表示已经挂起
FWorkEvent:TEvent; //正在工作事件
FPIsInterrupt:PBoolean; //中断
FDelayTime:Word; //延迟
FIsWorking:Boolean; //是否工作中
protected
SupervisorCtl:TObject; //管理者对象
MsgHandle:THandle; //消息目的窗口句柄
ErrorCount:Integer; //连续错误次数
procedure Execute; override;
procedure DoWorkProc(const APIsInterrupt:PBoolean); virtual; abstract; //实际的工作过程(虚方法,子类必须实现)
public
constructor Create(ASupervisorCtl:TObject; AMsgHandle:THandle; ADelayTime:Word);
destructor Destroy; override;
function ExitThread(const AWaitTime:Integer):Boolean; //退出线程
function SuspendThread(const AWaitTime:Integer):Boolean; //挂起线程
function ResumeThread(const AWaitTime:Integer):Boolean; //恢复线程
function WaitForWorkCompleted(const AWaitTime:Integer):Boolean; //等待线程工作完成
end;
implementation
{ THardWorkThread }
constructor THardWorkThread.Create(ASupervisorCtl: TObject; AMsgHandle: THandle; ADelayTime:Word);
begin
inherited Create(True);
SupervisorCtl:=ASupervisorCtl;
MsgHandle:=AMsgHandle;
FQuitEvent:=TEvent.Create;
FSuspendEvent:=TEvent.Create;
FWorkEvent:=TEvent.Create;
New(FPIsInterrupt);
FPIsInterrupt^:=False;
FIsWorking:=False;
ErrorCount:=0;
FDelayTime:=ADelayTime;
end;
destructor THardWorkThread.Destroy;
begin
Dispose(FPIsInterrupt);
FWorkEvent.Free;
FSuspendEvent.Free;
FQuitEvent.Free;
inherited;
end;
{
procedure THardWorkThread.DoWorkProc;
begin
end;
}
procedure THardWorkThread.Execute;
var
Msg:TMsg;
begin
FreeOnTerminate:=True;
while True do
begin
if PeekMessage(Msg,0,0,0,PM_REMOVE) then
begin
if Msg.message = WM_QUIT_HARD_THREAD then
begin
FQuitEvent.SetEvent;
Break;
end;
end;
if FPIsInterrupt^ then
begin
Continue;
end;
FSuspendEvent.WaitFor(INFINITE);
if FPIsInterrupt^ then
begin
Continue;
end;
FIsWorking:=True;
FWorkEvent.ResetEvent;
try
DoWorkProc(FPIsInterrupt);
finally
FWorkEvent.SetEvent;
FIsWorking:=False;
end;
if FDelayTime > DELAY_TIME_MIN then
begin
if DelayCanInterrupt(FDelayTime,FPIsInterrupt) then
Continue;
end;
end;
end;
function THardWorkThread.ExitThread(const AWaitTime: Integer): Boolean;
begin
Result:=True;
PostThreadMessage(ThreadID,WM_QUIT_HARD_THREAD,0,0);
FPIsInterrupt^:=True;
if FQuitEvent.WaitFor(AWaitTime) = wrTimeOut then
Result:=False;
end;
function THardWorkThread.ResumeThread(const AWaitTime: Integer): Boolean;
begin
FSuspendEvent.SetEvent;
Result:=True;
end;
function THardWorkThread.SuspendThread(const AWaitTime: Integer): Boolean;
const
Def_WaitTime = 10;
begin
Result:=False;
if FSuspendEvent.WaitFor(Def_WaitTime) = wrSignaled then
begin
if WaitForWorkCompleted(AWaitTime) then
begin
FSuspendEvent.ResetEvent;
Result:=True;
end;
end
else
begin
FSuspendEvent.ResetEvent;
Result:=True;
end;
end;
function THardWorkThread.WaitForWorkCompleted(const AWaitTime: Integer): Boolean;
begin
if FIsWorking then
Result:=FWorkEvent.WaitFor(AWaitTime) = wrSignaled
else
Result:=True;
end;
end.
这里用了workevent,isworking,suspendevent,感觉有点乱,暂时还不清楚怎么简化。