本文系原创,可以无条件转载、复制和传播,但请注明出处,并保留本版权声明。
出处:http://blog.csdn.net/shamork
作者:shamork shamork [AT] 163.com([AT]
为@)
本文系原创,可以无条件转载、复制和传播,但请注明出处,并保留本版权声明。
看了很长时间的资料了,一直没敢用多线程,一方面感觉太复杂,牵扯的东西太多,不敢随便下手,另一方面也是自己还没理解透,尝试了几次不得要领。今天下班路上边骑车边想,终于有了点眉目。总结如下:
1.线程执行函数一般没有参数(目前只知道C#有个带object参数的)
2.一般的同步函数也没有参数,例如invoke、synchronize等
3.并不是所有线程相关的代码都要用临界区隔离,而是有可能被多个线程访问的才需要
4.由于整体封装的需要以及以上三个原因,一般将线程函数封装到类中,这样就可以实现线程的参数化,也能将线程包装起来,减少外部使用时的复杂度
实现方式如下图所示:
经过包装之后,呵呵,至少线程函数就有参数了,同步代码也类似实现就行了。不过略麻烦,因为没有参数,所以只能一个函数对应一个私有变量。
晚上想了下,同步代码也可以类似封装,而且也不复杂,由于只会被线程访问,因此简单的写个函数包装一下私有变量就行了。
下面是个列子,新建一个application,在Form中建立两个按钮,一个文本框,一个label,一个memo,按如下命名
memo1: TMemo;
btnCreate: TButton;//创建/停止按钮
edtCnt: TEdit; //线程数
Label1: TLabel; //caption:个
btnClear: TButton;//清空memo
然后下面代码覆盖unit1,。
注意版本:Delphi7
结果如下:
unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TestThread = class(TThread) private { Private declarations } //内部变量,创建线程时保存参数,这些参数只对类内对象可见,所以很安全 Cnt: Cardinal; FHandle: THandle; FintV: Int64; Findex: Integer; protected procedure Execute; override; procedure AddString;//同步调用代码 procedure AddErrString;//同步调用代码 procedure AddOKString;//同步调用代码 public constructor Create(bSuspend: Boolean; index: Integer; intv: Int64 = 50);{参数进去了} end; TForm1 = class(TForm) memo1: TMemo; btnCreate: TButton; edtCnt: TEdit; Label1: TLabel; btnClear: TButton; procedure FormCreate(Sender: TObject); procedure FormClose(Sender: TObject; var Action: TCloseAction); procedure btnClearClick(Sender: TObject); procedure btnCreateClick(Sender: TObject); private { Private declarations } public { Public declarations } sText: string; procedure EndThread; end; var Form1: TForm1; thl: TList; implementation {$R *.dfm} { Important: Methods and properties of objects in visual components can only be used in a method called using Synchronize, for example, Synchronize(UpdateCaption); and UpdateCaption could look like, procedure TestThread.UpdateCaption; begin Form1.Caption := 'Updated in a thread'; end; } { TestThread } constructor TestThread.Create(bSuspend: Boolean; index: Integer; intv: Int64 = 50); begin FintV := intv; Findex := index; inherited Create(bSuspend); end; procedure TestThread.AddErrString; begin Form1.memo1.Lines.add('创建waitable timer 失败!'); end; //其实这个也可以包装的,例如 {procedure AddString(str:string); begin sText:=str; Synchronize(addStr);//addStr里操作sTest私有变量的值 end; } procedure TestThread.AddOKString;//这里没参数,因此函数与不同的动作对应即可,但是这样就要多搞几个函数了 begin Form1.memo1.Lines.add('Index: ' + IntToStr(Findex) + ' Interval: ' + IntToStr(FintV) + ' ThreadID:' + inttostr(self.ThreadID) + '创建成功!'); end; procedure TestThread.AddString; begin Form1.memo1.Lines.add('Index: ' + IntToStr(Findex) + ' Interval: ' + IntToStr(FintV) + ' ThreadID: ' + inttostr(self.ThreadID) + ' Time: ' + IntToStr(Cnt)); end; procedure TestThread.Execute; var dt: Int64; begin { Place thread code here } dt := 10; FHandle := CreateWaitableTimer(nil, False, nil); if FHandle < 1 then begin Synchronize(AddErrString); end else Synchronize(AddOKString); SetWaitableTimer(FHandle, dt, FintV, nil, nil, False); while (not Self.Terminated) and (WaitForSingleObject(FHandle, 1000) = WAIT_OBJECT_0) do begin Inc(Cnt); Synchronize(AddString); end; end; procedure TForm1.FormCreate(Sender: TObject); begin thl := TList.Create; end; procedure TForm1.EndThread; begin if thl.Count > 0 then begin while (thl.Count > 0) do begin TestThread(thl.Items[0]).Terminate; thl.Delete(0); end; memo1.Lines.Add('All Threads Teminated!'); end; end; procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction); begin EndThread; end; procedure TForm1.btnClearClick(Sender: TObject); begin memo1.Clear; end; procedure TForm1.btnCreateClick(Sender: TObject); var i, j, k: Integer; begin if thl.Count > 0 then begin EndThread; end else begin j := StrToInt(Trim(edtCnt.Text)); for i := 0 to j do begin k := 29 + i * 130; thl.Add(TestThread.Create(False, i, k)); Sleep(23); end; memo1.Lines.Add('All Threads Create OK!'); end; if thl.Count > 0 then btnCreate.Caption := '终止' else btnCreate.Caption := '创建'; end; end.