補充: 多線程編程知識 (多線程是必須逾越過去~~)
1. 示例 :
procedure TForm1.Button1Click(Sender: TObject);
var
i: Integer;
begin
for i := 0 to 500000 do
begin
Canvas.TextOut(10, 10, IntToStr(i));
Application.ProcessMessages; // 一般在比較費時的循環中加入 ProcessMessages,以便可以響應其他消息 ~~ 不是多線程
end;
end;
標準線程 :
a. > 調用 API 創建線程
function myfun(p : Pointer) : integer;stdcall;
var
i : integer;
begin
for i := 1 to 500000 do
begin
Form1.Canvas.Lock; // 多線程中必須加鎖
Form1.Canvas.Textout(100,200,Inttostr(i));
Form1.Canvas.Unlock; // 解鎖
end;
Result := 0;
end;
var ID : THandle;
CreateThread(nil,0,@myfun,nil,0,ID); // 調用 API 創建線程,新建線程執行方法 myfun;
CreateThread 第三個參數是函數指針,新建的線程建立後立即執行該函數,函數執行完後立即銷毀此線程。
調用的函數必須系統級的,不能屬於某一個類的函數,因此必須加上 stdcall,並且必須具有給定的(參數,返回值)格式,即使用不上也要加上。
CreateThead還必須接受函數的 THandle。
B. > TThread 類
Type TMyThread = class(TThread) // TThread 是一個抽像類,必須繼承使用
protected
procedure Execute; override;
end;
procdure TMyThread.Execute;
var
i : Integer;
begin
inherited;
FreeOnTerminate := True; // 線程執行完後立即結束
For i :=0 to 500000 then
begin
Form1.Canvas.Lock; // 多線程中必須加鎖
Form1.Canvas.Textout(100,200,Inttostr(i));
Form1.Canvas.Unlock; // 解鎖
end;
end;
procdure TForm1.Button1Click (Sender : TObject);
var
MyThread : TMyThread;
begin
MyThread := TMyThread.Create(false);
end;
CreateThread 另外可參見 CreateRemoteThread (建立其它進程中的線程)
CreateThread 返回線程句柄;句柄類似於指針,但句柄只是用來使用對象;有句柄的對象一般為內核對象。
當有多個線程在運行時,系統自動在每個線程中切換執行;線程的數據狀態保持在結構 TContext 中,其相對於一個 CPU寄存器的集合,
可以通過 GetThreadContent 獲得。
線程句柄 and 線程ID : 線程ID 是唯一的;而句柄可以有多個,GetCurrentThread 返回的是一個偽句柄,DuplicateHandle 用來複製一個句柄。
在主線程中 ,GetCurrentThreadID,MainThreadID,MainInstance 返回的是主線程ID。
function CreateThread(
lpThreadAttributes: Pointer;
dwStackSize: DWORD;
lpStartAddress: TFNThreadStartRoutine;
lpParameter: Pointer;
dwCreationFlags: DWORD; // 啟動選項
var lpThreadId: DWORD
): THandle; stdcall;
dwCreationFlags : 啟動選項,有2個值:
0 : 線程建立後立即執行入口函數;
CREATE_SUSPENDED : 線程建立後掛起等待;
可用 ResumeThread恢復線程執行; SuspendedThread 再次掛起;
第四個參數: 線程入口函數的參數 -- lpParameter, 可以指定任何參數。
第三個參數: lpStartAddress 入口函數指針, DWORD 類型 .
可以使用 GetExitCodeThread 函數獲得退出碼,即為此返回值.
** 入口函數不能為類的方法。
第二個參數: dwStackSize: DWORD; 分配給線程的堆棧大小。
第一個參數: lpThreadAttributes : 安全設置, 其指向 TSecurityAttributes結構,
一般為 nil , 表示沒有訪問限制 .
線程同步一般使用四個系統內核對象:
1. 事件 -- CreateEvent;
2. 互斥 -- CreateMutex;
3. 信號 -- CreateSemaphore;
4. 計時器--CreateWaitableTimer;
比較簡單的同步手段是 CriticalSection (臨界區),其不屬於內核對象,沒有句柄,也不需要跨進程使用。
// 臨界區示例 ******
定義臨界區: CS : TRTLCriticalSection ;
在線程函數中加入:
EnterCriticalSection(CS);
...
LeaveCriticalSection(CS);
FormCreate 中 : InitializeCriticalSection(CS);
FormDestory中 : DeleteCriticalSectioin(CS);
// 臨界區示例 ******
等待函數 : WaitForSingleObject
function WaitForSingleObject(
hHandle: THandle; {要等待的對象句柄}
dwMilliseconds: DWORD {等待的時間--毫秒}
): DWORD; stdcall;
返回值如下:
WAIT_OBJECT_0 : 剛好等著了
WAIT_TIMEOUT : 等過了點
WAIT_ABANDONED: 互斥對象不讓執行