procedure TForm1.Button1Click(Sender: TObject); var i: Integer; begin for i := 0to500000do begin Canvas.TextOut(10, 10, IntToStr(i)); Application.ProcessMessages; end; end;
function MyFun: Integer; var i: Integer; begin for i := 0to500000do begin Form1.Canvas.Lock; Form1.Canvas.TextOut(10, 10, IntToStr(i)); Form1.Canvas.Unlock; end; Result := 0; end;
procedure TForm1.Button1Click(Sender: TObject); begin MyFun; end;
在 Delphi 中使用多线程有两种方法: 调用 API、使用 TThread 类; 使用 API 的代码更简单.
function MyFun(p: Pointer): Integer; stdcall; var i: Integer; begin for i := 0to500000do begin Form1.Canvas.Lock; Form1.Canvas.TextOut(10, 10, IntToStr(i)); Form1.Canvas.Unlock; end; Result := 0; end;
procedure TForm1.Button1Click(Sender: TObject); var ID: THandle; begin CreateThread(nil, 0, @MyFun, nil, 0, ID); end;
CreateThread 还需要一个 var 参数来接受新建线程的 ID, 尽管暂时没用, 但这也是格式; 其他参数以后再说吧.
这样一个最简单的多线程程序就出来了, 咱们再用 TThread 类实现一次
type TMyThread = class(TThread) protected procedure Execute; override; end;
procedure TMyThread.Execute; var i: Integer; begin FreeOnTerminate := True; {这可以让线程执行完毕后随即释放} for i := 0to500000do begin Form1.Canvas.Lock; Form1.Canvas.TextOut(10, 10, IntToStr(i)); Form1.Canvas.Unlock; end; end;
procedure TForm1.Button1Click(Sender: TObject); begin TMyThread.Create(False); end;
var hThread: THandle; {线程句柄} num: Integer; {全局变量, 用于记录随机数}
{线程入口函数} function MyThreadFun(p: Pointer): Integer; stdcall; begin while True do{假如线程不挂起, 这个循环将一直循环下去} begin num := Random(100); end; Result := 0; end;
{建立并挂起线程} procedure TForm1.Button1Click(Sender: TObject); var ID: DWORD; begin hThread := CreateThread(nil, 0, @MyThreadFun, nil, CREATE_SUSPENDED, ID); Button1.Enabled := False; end;
{唤醒并继续线程} procedure TForm1.Button2Click(Sender: TObject); begin ResumeThread(hThread); end;
{挂起线程} procedure TForm1.Button3Click(Sender: TObject); begin SuspendThread(hThread); end;
procedure TForm1.FormCreate(Sender: TObject); begin Timer1.Interval := 100; end;
procedure TForm1.Timer1Timer(Sender: TObject); begin Text := IntToStr(num); end;
end.
㈢、入口函数的参数
function CreateThread( lpThreadAttributes: Pointer; dwStackSize: DWORD; lpStartAddress: TFNThreadStartRoutine; lpParameter: Pointer; {入口函数的参数} dwCreationFlags: DWORD; var lpThreadId: DWORD ): THandle; stdcall;
function MyThreadFun(p: Pointer): Integer; stdcall; var i: Integer; pt2: TPoint; {因为指针参数给的点随时都在变, 需用线程的局部变量存起来} begin pt2 := PPoint(p)^; {转换} for i := 0to1000000do begin with Form1.Canvas dobegin Lock; TextOut(pt2.X, pt2.Y, IntToStr(i)); Unlock; end; end; Result := 0; end;
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 := 0to1000000do begin with Form1.Canvas dobegin Lock; TextOut(x, y, IntToStr(i)); Unlock; end; end; Result := 0; end;
{线程入口函数} function MyThreadFun(p: Pointer): DWORD; stdcall; begin Form1.FormProc; {调用 TForm1 类的方法} Result := 99; {这个返回值将成为线程的退出代码, 99 是我随意给的数字} end;
{TForm1 的方法, 本例中是给线程的入口函数调用的} procedure TForm1.FormProc; var i: Integer; begin for i := 0to200000do begin with Form1.Canvas dobegin 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 = 0then begin Text := '线程还未启动'; Exit; end;
if ExitCode = STILL_ACTIVE then Text := Format('线程退出代码是: %d, 表示线程还未退出', [ExitCode]) else Text := Format('线程已退出, 退出代码是: %d', [ExitCode]); end;
end.
㈤、堆栈大小
function CreateThread( lpThreadAttributes: Pointer; dwStackSize: DWORD; {堆栈大小} lpStartAddress: TFNThreadStartRoutine; lpParameter: Pointer; dwCreationFlags: DWORD; var lpThreadId: DWORD ): THandle; stdcall;
什么是堆栈? 其实堆是堆、栈是栈, 有时 "栈" 也被叫做 "堆栈". 它们都是进程中的内存区域, 主要是存取方式不同(栈:先进后出; 堆:先进先出); "栈"(或叫堆栈)适合存取临时而轻便的变量, 主要用来储存局部变量; 譬如 for i := 0 to 99 do 中的 i 就只能存于栈中, 你把一个全局的变量用于 for 循环计数是不可以的.
function MyThreadFun(p: Pointer): DWORD; stdcall; var py: Integer; begin py := Integer(p); while True do begin Inc(num); with Form1.Canvas dobegin 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.
㈥、安全设置
function CreateThread( lpThreadAttributes: Pointer; {安全设置} dwStackSize: DWORD; lpStartAddress: TFNThreadStartRoutine; lpParameter: Pointer; dwCreationFlags: DWORD; var lpThreadId: DWORD ): THandle; stdcall;
function MyThreadFun(p: Pointer): DWORD; stdcall; var i: Integer; begin EnterCriticalSection(CS); for i := 0to99do Form1.ListBox1.Items.Add(IntToStr(i)); LeaveCriticalSection(CS); Result := 0; end;
请发表评论