做项目再次涉及到多线程的操作,曾经分时段研究了下多线程,每隔一段时间研究,总会多一点新的感悟和理解。
整理下,后续随时总结记录吧
1. 先谈谈两个命令,引出TEvent
Suspend 和 Resume 两个命令,一个是暂停,一个是恢复继续执行
因为两个命令自XE开始被标识为 deprecated, 而且不符合多线程安全(看了下TEvent说明,大致是因为TEven更适合TThread中进行多线程安全的操控)
所以在此引入TEvent控制TThread
//需要使用 TEvent,必须先 uses System.SyncObjs;
//官方函数说明
constructor Create(
//Set the EventAttributes parameter to specify the access rights and inheritance capabilities of the new event object. Calling Create with EventAttributes set to nil (Delphi) or NULL (C++) creates an event object with a default set of security attributes. If the TEvent object is created to access an existing named event object, only the bInheritHandle field of EventAttributes is used, as the access rights were determined when the event object was created.
EventAttributes: PSecurityAttributes;
//Set ManualReset to specify whether the signal of the TEvent object can only be turned off by a call to the ResetEvent method, or whether it is automatically reset when a single waiting thread is released. When ManualReset is true, the TEvent signal stays set until the ResetEvent method turns it off. When ManualReset is false, the signal is automatically turned off when only a single thread waits on the signal and that thread is released. If the TEvent object is created to access an existing named event object, the ManualReset parameter is ignored.
ManualReset,
//Set InitialState to indicate whether the TEvent object should be created with the signal set, or turned off. When InitialState is true, the TEvent object is created with the signal set. If the TEvent object is created to access an existing named event object, the InitialState parameter is ignored.
InitialState: Boolean;
//Set Name to provide a name for a new event object or to specify an existing named event object. If no other thread or process will need to access the event object to wait for its signal, Name can be left blank. Name can be a string of up to 260 characters, not including the backslash character (\). If Name is used to specify an existing event object, the value must match the name of the existing event in a case-sensitive comparison. If Name matches the name of an existing semaphore, mutex, or file-mapping object, the TEvent object will be created with Handle set to 0 and all method calls will fail.
const Name: String;
//Set UseCOMWait to True to ensure that when a thread is blocked and waiting for the object, any STA COM calls can be made back into this thread.
UseCOMWait: Boolean = False
); overload;
a. 我们先创建TEvent,
TEvent.Create(
nil, //使用默认的继承对象
true,//因为后续需要手工暂停线程,所以这边要设置手动复位信号
false,//因为我们希望线程创建后不立刻执行,所以这边初始化状态 Siganl 设置为False
'' //一般只用于个线程中,则留空吧,不需要区分多 TEvent
)
b.线程中设置一个信号复位函数用于供外部主线程控制线程
procedure TTest.Start;
begin
Event.SetEvent;
end;
c.线程中TThread.Execute中 TEvent 的控制体现
procedure TTest.Execute;
begin
Event.WaitFor; //线程耐心等线程进行 SetEvent 给初始化信号
//获取信号后执行
Event.ResetEvent;
while not terminated do
begin
//--------------------------
//线程不释放,在此处进行其他命令的执行
.....
//--------------------------
//一直等待信号中
Event.WaitFor;
Event.ResetEvent;
end;
end;
d.线程完毕后释放时,对TEvent进行处理
destructor TTest.Destroy;
begin
Event.Free;
inherited;
end;
-----------------------------------------------
完整代码
unit XXX
interface
uses
System.Classes, Sytem.SyncObjs;
Type
TTest = class(TThread)
....
private
Event: TEvent;
procedure Execute;
public
constructor Create; overload;
destructor Destroy; override;
procedure Start; //******用于外部控制线程的函数
end;
TFrm_XXX = class(TForm)
FTest: TTest;
procedure Btn_StartOnClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormDestory(Sender: TObject);
end;
var
Frm_XXX: TFrm_XXX;
implementation
constructor TTest.Create;
begin
inherited Create(true);
Event := TEvent.Create(nil,true,false,'');
end;
destructor TTest.Destroy;
begin
Event.Free;
inherited;
end;
procedure TTest.Execute;
begin
Event.WaitFor;
Event.ResetEvent;
While not Terminated do
begin
.....
Event.WaitFor;
Event.ResetEvent;
end;
end;
procedure TTest.Start;
begin
Event.SetEvent;
end;
procedure TFrm_XXX.Btn_StartOnClick(Sender: TObject);
begin
//多线程开动
FTest.Start;
end;
procedure TFrm_XXX.FormCreate(Sender: TObject);
begin
FTest := TTest.Create;
FTest.FreeOnTerminate := true;
//此处完整的线程对接,还需要给线程一个Sync到主线程的函数用以同步线程空间相关数据的反馈
//不过不在这边讨论
end;
procedure TFrm_XXX.FormDestory(Sender: TObject);
begin
FTest.Terminate;
FTest.Start;
end;
2. 留位 (线程结果同步到出现中中)