ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

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

2021-04-30 12:52:16  阅读:189  来源: 互联网

标签:begin end CreateThread 续二 线程 var Integer 多线程 Pointer


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

function CreateThread(
  lpThreadAttributes: Pointer;
  dwStackSize: DWORD;
  lpStartAddress: TFNThreadStartRoutine;
  lpParameter: Pointer;  {入口函数的参数}
  dwCreationFlags: DWORD;
  var lpThreadId: DWORD
): THandle; stdcall;

线程入口函数的参数是个无类型指针(Pointer), 用它可以指定任何数据; 本例是把鼠标点击窗体的坐标传递给线程的入口函数, 每次点击窗体都会创建一个线程.

运行效果图:

o_092111.gif

代码文件:
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
  onm ouseUp = 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.

posted on 2009-02-11 10:42  万一  阅读(15770)  评论(25)  编辑  收藏

标签:begin,end,CreateThread,续二,线程,var,Integer,多线程,Pointer
来源: https://blog.51cto.com/u_14617575/2745709

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有