• 多线程编程(5) 从 CreateThread 说起[续三]


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

    到了入口函数了, 学到这个地方, 我查了一个入口函数的标准定义, 这个函数的标准返回值应该是 DWORD, 不过这函数在 Delphi 的 System 单元定义的是: TThreadFunc = function(Parameter: Pointer): Integer; 我以后会尽量使用 DWORD 做入口函数的返回值.

    这个返回值有什么用呢?
    等线程退出后, 我们用 GetExitCodeThread 函数获取的退出码就是这个返回值!

    如果线程没有退出, GetExitCodeThread 获取的退出码将是一个常量 STILL_ACTIVE (259); 这样我们就可以通过退出码来判断线程是否已退出.

    还有一个问题: 前面也提到过, 线程函数不能是某个类的方法! 假如我们非要线程去执行类中的一个方法能否实现呢?
    尽管可以用 Addr(类名.方法名) 或 MethodAddress('published 区的方法名') 获取类中方法的地址, 但都不能当做线程的入口函数, 原因可能是因为类中的方法的地址是在实例化为对象时动态分配的.
    后来换了个思路, 其实很简单: 在线程函数中再调用方法不就得了, 估计 TThread 也应该是这样.

    下面的例子就尝试了用线程调用 TForm1 类中的方法, 并测试了退出码的相关问题.

    本例效果图:



    代码文件:
    unit Unit1;
    
    interface
    
    uses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs, StdCtrls;
    
    type
      TForm1 = class(TForm)
        Button1: TButton;
        Button2: TButton;
        procedure Button1Click(Sender: TObject);
        procedure Button2Click(Sender: TObject);
        private
          procedure FormProc; {准备给线程使用的方法}
      end;
    
    var
      Form1: TForm1;
    
    implementation
    
    {$R *.dfm}
    
    var
      hThread: THandle;
    
    {线程入口函数}
    function MyThreadFun(p: Pointer): DWORD; stdcall;
    begin
      Form1.FormProc; {调用 TForm1 类的方法}
      Result := 99;   {这个返回值将成为线程的退出代码, 99 是我随意给的数字}
    end;
    
    {TForm1 的方法, 本例中是给线程的入口函数调用的}
    procedure TForm1.FormProc;
    var
      i: Integer;
    begin
      for i := 0 to 200000 do
      begin
        with Form1.Canvas do begin
          Lock;
          TextOut(10, 10, IntToStr(i));
          Unlock;
        end;
      end;
    end;
    
    {建立并执行线程}
    procedure TForm1.Button1Click(Sender: TObject);
    var
      ID: DWORD;
    begin
      hThread := CreateThread(nil, 0, @MyThreadFun, nil, 0, ID);
    end;
    
    {获取线程的退出代码, 并判断线程是否退出}
    procedure TForm1.Button2Click(Sender: TObject);
    var
      ExitCode: DWORD;
    begin
      GetExitCodeThread(hThread, ExitCode);
    
      if hThread = 0 then
      begin
        Text := '线程还未启动';
        Exit;
      end;
    
      if ExitCode = STILL_ACTIVE then
        Text := Format('线程退出代码是: %d, 表示线程还未退出', [ExitCode])
      else
        Text := Format('线程已退出, 退出代码是: %d', [ExitCode]);
    end;
    
    end.
    

    窗体文件:
    object Form1: TForm1
      Left = 0
      Top = 0
      Caption = 'Form1'
      ClientHeight = 84
      ClientWidth = 376
      Color = clBtnFace
      Font.Charset = DEFAULT_CHARSET
      Font.Color = clWindowText
      Font.Height = -11
      Font.Name = 'Tahoma'
      Font.Style = []
      OldCreateOrder = False
      PixelsPerInch = 96
      TextHeight = 13
      object Button1: TButton
        Left = 183
        Top = 32
        Width = 75
        Height = 25
        Caption = 'Button1'
        TabOrder = 0
        OnClick = Button1Click
      end
      object Button2: TButton
        Left = 280
        Top = 32
        Width = 75
        Height = 25
        Caption = 'Button2'
        TabOrder = 1
        OnClick = Button2Click
      end
    end
    

  • 相关阅读:
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
    数据库作业15:关系数据理论
    IPv6 — 实践
    Provisional headers are shown 说明走了缓存没有发送请求
  • 原文地址:https://www.cnblogs.com/del/p/1388321.html
Copyright © 2020-2023  润新知