VCL对象不是线程安全的,而且它们的属性和方法必须要从VCL主线程中进行访问或被执行,但有两种VCL对象是例外的情况,它们是线程安全的。一种是任何图形对象,另一种是TThreadList。
这意味着不必非得在主VCL线程中才能设置一个画布的画笔颜色,或画刷类型,可以在另一个线程的环境中完成一点。对于图形对象,使用Lock和UnLock,而对于ThreadList,则使用LockList和UnLockList,这些方法的行为类似于临界区,在调用它们的时候会阻止其他线程的执行。因为Lock会中断所有线程的执行,所以如果使用不正确的话,应用程序性能会有很大下降。比如:
Form1.Canvas.Lock;
For i := 0 to 10000 do
begin
Form1.Canvas.TextOut(20,20,str);
end;
Form1.Canvas.UnLock;上面这个代码中,Lock后再循环,则循环结构过于拥挤,锁定时间过长。所以应该将Lock与UnLock放在循环里面。
下面的例子,通过多线程对窗体画布进行画线。点“开始”菜单创建N个线程同时往窗体画线,点“结束”同时终止N个线程。
- unit Main;
- interface
- uses
- Windows, Messages, SysUtils, Variants, Classes,
- Graphics, Controls, Forms, Dialogs, Menus;
- type
- TForm2 = class(TForm)
- MainMenu1: TMainMenu;
- S1: TMenuItem;
- T1: TMenuItem;
- procedure S1Click(Sender: TObject);
- procedure T1Click(Sender: TObject);
- procedure FormCreate(Sender: TObject);
- procedure FormDestroy(Sender: TObject);
- private
- { Private declarations }
- public
- { Public declarations }
- end;
- var
- Form2: TForm2;
- List:TList;
- implementation
- uses DrawThread;
- {$R *.dfm}
- procedure TForm2.FormCreate(Sender: TObject);
- begin
- List:=TList.Create;
- end;
- procedure TForm2.FormDestroy(Sender: TObject);
- begin
- List.Free;
- end;
- //“开始”菜单
- procedure TForm2.S1Click(Sender: TObject);
- var
- value:string;
- i: Integer;
- begin
- value:=InputBox('提示','请输入需要创建多少线程:','3');
- try
- for i := 0 to StrToInt(value) - 1 do
- List.Add(TDrawThread.create(self));
- except
- on e:Exception do
- ShowMessage(e.Message);
- end;
- end;
- //“结束”菜单
- procedure TForm2.T1Click(Sender: TObject);
- var
- I: Integer;
- begin
- Cursor:=crHourGlass;
- try
- for I := List.Count - 1 downto 0 do
- begin
- TDrawThread(List[i]).Terminate;
- end;
- List.Clear;
- finally
- Cursor:=crDefault;
- end;
- ShowMessage('线程已终止');
- end;
- end.{多线程类}
- unit DrawThread;
- interface
- uses
- Classes,Forms;
- type
- TDrawThread = class(TThread)
- private
- { Private declarations }
- FForm:TForm;
- FWidth,FHeight:Integer;
- protected
- procedure Execute; override;
- public
- constructor create(AForm:TForm);
- end;
- implementation
- uses Main,Types,Windows;
- { TDrawThread }
- constructor TDrawThread.create(AForm: TForm);
- begin
- FForm:=AForm;
- FWidth:=FForm.Width;
- FHeight:=FForm.Height;
- Inherited Create(False);
- end;
- procedure TDrawThread.Execute;
- var
- p1,p2:TPoint;
- begin
- { Place thread code here }
- FreeOnTerminate:=True;
- while Not (Terminated or Application.Terminated) do
- begin
- Randomize;
- P1.X:=Random(FWidth);
- P1.Y:=Random(FHeight);
- P2.X:=Random(FWidth);
- P2.Y:=Random(FHeight);
- FForm.Canvas.Pen.Color:=RGB(Random(256),Random(256),Random(256));
- with FForm.Canvas do
- begin
- Lock;
- MoveTo(P1.X,P1.Y);
- LineTo(P2.X,p2.Y);
- UnLock;
- end;
- end;
- end;
- end.
运行情况如下(如果想看它慢慢画的话,只要在UnLock后加上Sleep(100)):