zoukankan      html  css  js  c++  java
  • 多线程编程(6) 从 CreateThread 说起[续四]

    function CreateThread(
      lpThreadAttributes: Pointer;
      dwStackSize: DWORD;  {堆栈大小}
      lpStartAddress: TFNThreadStartRoutine; 
      lpParameter: Pointer; 
      dwCreationFlags: DWORD;
      var lpThreadId: DWORD
    ): THandle; stdcall;
    

    CreateThread 的第二个参数是分配给线程的堆栈大小.
    这首先这可以让我们知道: 每个线程都有自己独立的堆栈(也拥有自己的消息队列).

    什么是堆栈? 其实堆是堆、栈是栈, 有时 "栈" 也被叫做 "堆栈".
    它们都是进程中的内存区域, 主要是存取方式不同(栈:先进后出; 堆:先进先出);
    "栈"(或叫堆栈)适合存取临时而轻便的变量, 主要用来储存局部变量; 譬如 for i := 0 to 99 do 中的 i 就只能存于栈中, 你把一个全局的变量用于 for 循环计数是不可以的.

    现在我们知道了线程有自己的 "栈", 并且在建立线程时可以分配栈的大小.

    前面所有的例子中, 这个值都是 0, 这表示使用系统默认的大小, 默认和主线程栈的大小一样, 如果不够用会自动增长;
    那主线程的栈有多大? 这个值是可以设定的: Project -> Options -> Delphi Compiler -> Linking(如图)



    栈是私有的但堆是公用的, 如果不同的线程都来使用一个全局变量有点乱套;
    为解决这个问题 Delphi 为我们提供了一个类似 var 的 ThreadVar 关键字, 线程在使用 ThreadVar 声明的全局变量时会在各自的栈中留一个副本, 这样就解决了冲突. 不过还是尽量使用局部变量, 或者在继承 TThread 时使用类的成员变量, 因为 ThreadVar 的效率不好, 据说比局部变量能慢 10 倍.

    在下面的例子就测试了用 var 和 ThreadVar 定义变量的不同.

    使用 var 效果图:


    使用 ThreadVar 效果图:


    代码文件:
    unit Unit1;
    
    interface
    
    uses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs, StdCtrls;
    
    type
      TForm1 = class(TForm)
        Button1: TButton;
        procedure Button1Click(Sender: TObject);
      end;
    
    var
      Form1: TForm1;
    
    implementation
    
    {$R *.dfm}
    
    //var num: Integer;     {全局变量}
    threadvar num: Integer; {支持多线程的全局变量}
    
    function MyThreadFun(p: Pointer): DWORD; stdcall;
    var
      py: Integer;
    begin
      py := Integer(p);
      while True do
      begin
        Inc(num);
        with Form1.Canvas do begin
          Lock;
          TextOut(20, py, IntToStr(num));
          Unlock;
        end;
        Sleep(1000); {然线程挂起 1 秒钟再继续}
      end;
    end;
    
    procedure TForm1.Button1Click(Sender: TObject);
    var
      ID: DWORD;
    begin
      {借入口函数的参数传递了一个坐标点中的 Y 值, 以让各线程把结果输出在不同位置}
      CreateThread(nil, 0, @MyThreadFun, Ptr(20), 0, ID);
      CreateThread(nil, 0, @MyThreadFun, Ptr(40), 0, ID);
      CreateThread(nil, 0, @MyThreadFun, Ptr(60), 0, ID);
    end;
    
    end.
    

    窗体文件:
    object Form1: TForm1
      Left = 0
      Top = 0
      Caption = 'Form1'
      ClientHeight = 106
      ClientWidth = 180
      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 = 80
        Top = 40
        Width = 75
        Height = 25
        Caption = 'Button1'
        TabOrder = 0
        OnClick = Button1Click
      end
    end
    

  • 相关阅读:
    使用Angular CLI生成 Angular 5项目
    asp.net core 2.0 web api + Identity Server 4 + angular 5 可运行前后台源码
    依赖反转原则DIP 与使用了Repository模式的asp.net core项目结构
    Git基本命令 -- 别名 + 忽略 + 推送
    Git基本命令 -- 历史
    多线程,论多核时代爱恨情仇
    凛冬将至,用几款特效暖暖身
    HTML5游戏开发引擎,初识CreateJS
    详解设计模式之工厂模式(简单工厂+工厂方法+抽象工厂)
    详解设计模式六大原则
  • 原文地址:https://www.cnblogs.com/del/p/1388700.html
Copyright © 2011-2022 走看看