多線程編程(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.

轉帖:http://www.cnblogs.com/del/archive/2009/02/11/1388008.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章