zoukankan      html  css  js  c++  java
  • 多线程编程(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.
    

  • 相关阅读:
    python2.7打印中文乱码的问题解决
    Tesseract5.0训练字库,提高OCR特殊场景识别率(一)
    git比较重要但是又容易忘记的操作
    ntp局域网时间同步操作
    Flask使用原生sql语句
    Linux的tail命令查看文件
    使用gitlab的webhook进行前端自动部署
    通过queue实现前端的被动接收
    互动interactive与多行输出
    复习
  • 原文地址:https://www.cnblogs.com/del/p/1388008.html
Copyright © 2011-2022 走看看