首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> Delphi

多線程程式設計(6):CreateThread 參數深度解析[續四]——堆疊大小與 ThreadVar

     編輯:Delphi

CreateThread 第二參數:dwStackSize 堆疊大小

每個線程擁有獨立的堆疊(Stack),用於儲存區域變數、函數呼叫鏈、參數傳遞等。dwStackSize 指定初始保留大小,單位位元組。

預設行為與調整

  • 0:使用主線程相同大小(預設 1 MB),不足時自動擴展至記憶體上限。
  • 指定值:系統會保留該大小的虛擬記憶體,實際提交按頁成長。
  • 主線程堆疊大小可在專案選項設定:
    Project → Options → Delphi Compiler → Linking → Stack Size

Delphi 專案堆疊大小設定

堆疊 vs 堆

特性Stack (堆疊)Heap (堆)
存取模式LIFO (後進先出)隨機存取
用途區域變數、呼叫框架動態記憶體分配
所有權線程私有進程共享
大小固定上限 (可擴展)動態增長
效能極快 (指針移動)較慢 (分配演算法)

ThreadVar:線程區域儲存 (TLS) 關鍵字

解決多線程共享全域變數衝突的 Delphi 語言級方案:

var
  g_Counter: Integer;        // 所有線程共享,需同步
  g_ThreadCounter: Integer;  // 錯誤示範:仍是共享

threadvar
  tls_Counter: Integer;      // 每個線程擁有獨立副本

實測對比:var vs ThreadVar

使用 var (共享):三條線程同時遞增同一變數,輸出交織、數值衝突:

var 共享變數衝突

使用 threadvar (獨立):每條線程維護自己的計數器,互不干擾:

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;       // TLS 版本

function MyThreadFun(p: Pointer): DWORD; stdcall;
var py: Integer;
begin
  py := Integer(p);           // 參數傳遞 Y 座標
  while True do
  begin
    Inc(num);
    with Form1.Canvas do
    begin
      Lock;
      TextOut(20, py, IntToStr(num));
      Unlock;
    end;
    Sleep(1000);
  end;
  Result := 0;
end;

procedure TForm1.Button1Click(Sender: TObject);
var ID: DWORD;
begin
  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.

ThreadVar 效能與最佳實踐

  • 效能代價:編譯器插入 TLS 存取指令,比區域變數慢約 10 倍(官方文檔數據)。
  • 建議:
    • 優先使用區域變數(函數參數、循環變數)
    • 繼承 TThread 時使用類別成員欄位(每個線程實例獨立)
    • 僅在無法避免全域狀態時使用 threadvar
  • 初始化/終結:threadvar 變數在線程啟動時自動初始化為 0/nil,線程結束時自動終結 (釋放介面、字串、動態陣列等)。

參數傳遞小技巧:32-bit 指釧攜帶 X,Y 座標

// 呼叫端
num := MakeLong(X, Y);        // 低 16-bit = X, 高 16-bit = Y
CreateThread(nil, 0, @MyThreadFun, Ptr(num), 0, ID);

// 線程端
x := LoWord(Integer(p));
y := HiWord(Integer(p));
// 或無 API 版本:
// x := Integer(p) and $FFFF;
// y := Integer(p) shr 16;

這正是 Windows 訊息 lParam 傳遞滑鼠座標的經典做法。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved