为解决这个问题 Delphi 为我们提供了一个类似 var 的 ThreadVar 关键字, 线程在使用 ThreadVar 声明的全局变量时会在各自的栈中留一个副本, 这样就解决了冲突. 不过还是尽量使用局部变量, 或者在继承 TThread 时使用类的成员变量, 因为 ThreadVar 的效率不好, 据说比局部变量能慢 10 倍.
在下面的例子就测试了用 var 和 ThreadVar 定义变量的不同.
使用 var 效果图
:
delphi多线程 delphi线程详细教程简单到复杂
使用 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;
delphi多线程 delphi线程详细教程简单到复杂
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);
delphi多线程 delphi线程详细教程简单到复杂
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.
㈥、安全设置
function CreateThread(
lpThreadAttributes: Pointer; {安全设置}
dwStackSize: DWORD;
lpStartAddress: TFNThreadStartRoutine;
lpParameter: Pointer;
dwCreationFlags: DWORD;
var lpThreadId: DWORD
): THandle; stdcall;
CreateThread 的第一个参数 lpThreadAttributes 是指向 TSecurityAttributes 结构的指针, 一般都是置为 nil, 这表示没有访问限制; 该结构的定义是:
//TSecurityAttributes(又名: SECURITY_ATTRIBUTES、_SECURITY_ATTRIBUTES)
_SECURITY_ATTRIBUTES = record
nLength: DWORD; {结构大小}
lpSecurityDescriptor: Pointer; {默认 nil; 这是另一个结构 TSecurityDescriptor 的指针}
delphi多线程 delphi线程详细教程简单到复杂
bInheritHandle: BOOL; {默认 False, 表示不可继承} end;
//TSecurityDescriptor(又名: SECURITY_DESCRIPTOR、_SECURITY_DESCRIPTOR)
_SECURITY_DESCRIPTOR = record
Revision: Byte;
Sbz1: Byte;
Control: SECURITY_DESCRIPTOR_CONTROL;
Owner: PSID;
Group: PSID;
Sacl: PACL;
Dacl: PACL;
end;
够复杂的, 但我们在多线程编程时不需要去设置它们, 大都是使用默认设置(也就是赋值为 nil).
我觉得有必要在此刻了解的是: 建立系统内核对象时一般都有这个属性(TSecurityAttributes);
在接下来多线程的课题中要使用一些内核对象, 不如先盘点一下, 到时碰到这个属性时给个 nil 即可, 不必再费神.
{建立事件}
function CreateEvent(
lpEventAttributes: PSecurityAttributes; {!}
bManualReset: BOOL;
bInitialState: BOOL;
lpName: PWideChar
): THandle; stdcall;
{建立互斥}
delphi多线程 delphi线程详细教程简单到复杂
function CreateMutex(
lpMutexAttributes: PSecurityAttributes; {!}
bInitialOwner: BOOL;
lpName: PWideChar
): THandle; stdcall;
{建立信号}
function CreateSemaphore(
lpSemaphoreAttributes: PSecurityAttributes; {!}
lInitialCount: Longint;
lMaximumCount: Longint;
lpName: PWideChar
): THandle; stdcall;
{建立等待计时器}
function CreateWaitableTimer(
lpTimerAttributes: PSecurityAttributes; {!}
bManualReset: BOOL;
lpTimerName: PWideChar
): THandle; stdcall;