典心作品集百度云:Delphi多线程编程 - 编程技巧文章 - 蓝鸟软件-04

来源:百度文库 编辑:中财网 时间:2024/04/27 21:54:29

多线程编程(4) - 从 CreateThread 说起[续二]。

  function CreateThread(
 lpThreadAttributes: Pointer;
 dwStackSize: DWORD;
 lpStartAddress: TFNThreadStartRoutine;
 lpParameter: Pointer; {入口函数的参数}
 dwCreationFlags: DWORD;
 var lpThreadId: DWORD
): THandle; stdcall;
  线程入口函数的参数是个无类型指针(Pointer), 用它可以指定任何数据; 本例是把鼠标点击窗体的坐标传递给线程的入口函数, 每次点击窗体都会创建一个线程.
  运行效果图:

  代码文件:unit Unit1;
interface
uses
 Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
 Dialogs;
type
 TForm1 = class(TForm)
  procedure FormMouseUp(Sender: TObject; Button: TMouseButton;
   Shift: TShiftState; X, Y: Integer);
 end;
var
 Form1: TForm1;
implementation
{$R *.dfm}
var
 pt: TPoint; {这个坐标点将会已指针的方式传递给线程, 它应该是全局的}
function MyThreadFun(p: Pointer): Integer; stdcall;
var
 i: Integer;
 pt2: TPoint;    {因为指针参数给的点随时都在变, 需用线程的局部变量存起来}
begin
 pt2 := PPoint(p)^; {转换}
 for i := 0 to 1000000 do
 begin
  with Form1.Canvas do begin
   Lock;
   TextOut(pt2.X, pt2.Y, IntToStr(i));
   Unlock;
  end;
 end;
 Result := 0;
end;

procedure TForm1.FormMouseUp(Sender: TObject; Button: TMouseButton;
 Shift: TShiftState; X, Y: Integer);
var
 ID: DWORD;
begin
 pt := Point(X, Y);
 CreateThread(nil, 0, @MyThreadFun, @pt, 0, ID);
 {下面这种写法更好理解, 其实不必, 因为 PPoint 会自动转换为 Pointer 的}
 //CreateThread(nil, 0, @MyThreadFun, Pointer(@pt), 0, ID);
end;
end.

 窗体文件:object Form1: TForm1
 Left = 0
 Top = 0
 Caption = 'Form1'
 ClientHeight = 128
 ClientWidth = 229
 Color = clBtnFace
 Font.Charset = DEFAULT_CHARSET
 Font.Color = clWindowText
 Font.Height = -11
 Font.Name = 'Tahoma'
 Font.Style = []
 OldCreateOrder = False
 OnMouseUp = FormMouseUp
 PixelsPerInch = 96
 TextHeight = 13
end

  这个例子还有不严谨的地方: 当一个线程 Lock 窗体的 Canvas 时, 其他线程在等待; 线程在等待时, 其中的计数也还在增加. 这也就是说: 现在并没有去处理线程的同步; 同步是多线程中最重要的课题, 快到了.

  另外有个小技巧: 线程函数的参数是个 32 位(4个字节)的指针, 仅就本例来讲, 可以让它的 "高16位" 和 "低16位" 分别携带 X 和 Y; 这样就不需要哪个全局的 pt 变量了.

  其实在 Windows 的消息中就是这样传递坐标的, 在 Windows 的消息中一般高字节是 Y、低字节是 X; 咱们这么来吧, 这样还可以使用给消息准备的一些方便的函数.

  重写本例代码(当然运行效果和窗体文件都是一样的):unit Unit1;
interface
uses
 Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
 Dialogs;
type
 TForm1 = class(TForm)
  procedure FormMouseUp(Sender: TObject; Button: TMouseButton;
   Shift: TShiftState; X, Y: Integer);
 end;
var
 Form1: TForm1;
implementation
{$R *.dfm}
function MyThreadFun(p: Pointer): Integer; stdcall;
var
 i: Integer;
 x,y: Word;
begin
 x := LoWord(Integer(p));
 y := HiWord(Integer(p));
 {如果不使用 LoWord、HiWord 函数可以像下面这样: }
 //x := Integer(p);
 //y := Integer(p) shr 16;
 for i := 0 to 1000000 do
 begin
  with Form1.Canvas do begin
   Lock;
   TextOut(x, y, IntToStr(i));
   Unlock;
  end;
 end;
 Result := 0;
end;

procedure TForm1.FormMouseUp(Sender: TObject; Button: TMouseButton;
 Shift: TShiftState; X, Y: Integer);
var
 ID: DWORD;
 num: Integer;
begin
 num := MakeLong(X, Y);
 {如果不使用 MekeLong、MakeWParam、MakeLParam、MakeResult 等函数, 可以像下面这样: }
 //num := Y shl 16 + X;
 CreateThread(nil, 0, @MyThreadFun, Ptr(num), 0, ID);
 {上面的 Ptr 是专门将一个数字转换为指针的函数, 当然也可以这样: }
 //CreateThread(nil, 0, @MyThreadFun, Pointer(num), 0, ID);
end;
end.