來源:互聯網網民 2006-12-12 19:18:08
評論線程中的變量
由于每個線程都代表了一個不同的執行路徑,因此,最好有一種只限于一個線程內部使用的數據,
要實現上述目的有以下幾種方式:
1、局部變量(基于棧),很簡單,在你的線程函數中你定義的變量既是如此。由于每個線程都在各自的棧中,各個線程將都有一套局部變量的副本,這樣,就不會相互影響。對于那些只在過程或函數的生存期有意義的變量,應當把它們聲明爲局部變量。
2、存儲在線程對象中。還記得CreateThread函數中的lpParameter參數嗎,它可以接受一個無類型的指針。結合本文第一章的內容,你應該還記得,它被存儲在線程內核對象的上下文結構中,你可以通過CONTEXT結構中的CONTEXT_INTEGER部分的ebx來讀取它的地址。
下面是一段示例代碼,用來演示讀取CONTEXT結構,這段代碼一般用不到,但它可以說明CrateThread函數中的lpParameter被存儲的位置
...{
作者:wudi_1982
聯系方式:wudi_1982@hotmail.com
轉載請著名出處,本代碼爲演示代碼,只貼出了一些關鍵部分
}
type
//傳遞給線程函數的結構和指針的聲明
Tinfo = record
count : integer;
x : integer;
y : integer;
end;
Pinfo= ^Tinfo;
var
MyThreadHad : THandle;//一個全局變量,用來保存線程的句柄
//線程函數
function MyThread(info : Pointer):DWORD; stdcall;
var
i : integer;
begin
//根據傳遞來信息決定在窗口的那個位置輸出什麽信息
for i := 0 to Pinfo(info)^.count-1 do
Form1.Image1.Canvas.TextOut(Pinfo(info)^.x,Pinfo(info)^.y,inttostr(i));
//FreeMem(info);
Result := 0;
end;
//創建一個線程
procedure TForm1.Button4Click(Sender: TObject);
var
ppi : Pinfo;
MyThreadId : DWORD;
begin
//分配空間並賦初值
ppi :=AllocMem(sizeof(tinfo));
ppi^.count := 1000000;
ppi^.x := 10;
ppi^.y := 10;
//創建
MyThreadHad := CreateThread(nil,0,@MyThread,ppi,CREATE_SUSPENDED,MyThreadId);
//在窗體上顯示線程函數的地址和傳遞給它的參數的地址
labThreadAddr.Caption := inttostr( integer(@MyThread));
labThreadPvparam.Caption := inttostr(integer(ppi));
end;
//讀取CONTEXT結構,注意CONTEXT結構是和CPU有關的,我這裏測試時,工作在intel的CPU上
procedure TForm1.btnRContextClick(Sender: TObject);
var
con : _CONTEXT;
begin
//初始化結構
con.ContextFlags := CONTEXT_FULL;
//讀取
GetThreadContext(MyThreadHad,con);
//顯示在窗體的listbox上
with lbxContextInfo.Items do
begin
// Clear;
Add('------------CONTEXT--------------');
Add('');
Add('CONTEXT_DEBUG_REGISTERS-----');
Add('dr0:'+#9+IntToStr(con.Dr0));
Add('dr1:'+#9+IntToStr(con.Dr1));
Add('dr2:'+#9+IntToStr(con.Dr2));
Add('dr3:'+#9+IntToStr(con.Dr3));
Add('dr6:'+#9+IntToStr(con.Dr6));
Add('dr7:'+#9+IntToStr(con.Dr7));
add('CONTEXT_SEGMENTS---------');
Add('segGs:'+#9+inttostr(con.SegGs));
Add('segFs:'+#9+inttostr(con.Segfs));
Add('segEs:'+#9+inttostr(con.Seges));
Add('segDs:'+#9+inttostr(con.Segds));
Add('CONTEXT_INTEGER.---------');
Add('edi: '+#9+IntToStr(con.Edi));
Add('esi: '+#9+IntToStr(con.Esi));
Add('ebx: '+#9+IntToStr(con.Ebx));
Add('edx: '+#9+IntToStr(con.Edx));
Add('ecx: '+#9+IntToStr(con.Ecx));
Add('eax: '+#9+IntToStr(con.Eax));
Add('CONTEXT_CONTROL----------');
Add('Ebp: '+#9+IntToStr(con.Ebp));
Add('Eip: '+#9+IntToStr(con.Eip));
Add('segcs: '+#9+IntToStr(con.SegCs));
Add('EFlags: '+#9+IntToStr(con.EFlags));
Add('Esp: '+#9+IntToStr(con.Esp));
Add('SegSs: '+#9+IntToStr(con.SegSs));
end;
end;
把上面代碼整理之後,添加到你的程序中,你可以發現(如果也是intel的CPU),那麽你可以從Eax寄存器讀取到線程函數的地址,從Ebx中讀取到傳遞給線程函數的參數地址。
在DELPHI中的TThread對象的構造函數中,你可以看到這段代碼
FHandle := BeginThread(nil, 0, @ThreadProc, Pointer(Self), CREATE_SUSPENDED, FThreadID);
再觀察BeginThread的實現,你會發現TThread的調用CreateThread時,將Pointer(Self),也就是TThread對象本身當作線程函數的參數傳遞過去,換言之,你在TThread的派生類中定義的變量,對于一個線程而言,將存儲在這個線程單獨的堆棧中,而它在堆棧的地址存儲在線程的上下文結構中。
可以做一個簡單的試驗,將一個線程生成多次,你可以發現存儲在線程對象內部的變量將互不影響。
說到這裏,必須談論一個問題,效率的問題,我在一本書上曾經看到過這樣一段話“由于訪問線程對象中的數據比訪問線程局部變量要快10倍,因此,你應當盡可能地把線程專用的信息保存在線程對象中。”對此,我一直沒有特別理解。如果一定要相信這句話,那我會這麽理解,就是存儲在線程對象中的變量因爲上下文結構記錄了它的地址等原因,所以它更快。盡信書不如無書,我還在思考,不過好在這種速度的影響對于通常的使用而言影響不大。
3、在DELPHI中,用Object Pascal的關鍵字threadvar來聲明變量,以利用操作系統級的線程局部存儲。
在前面我們了解到:雖然對于局部變量,在每個線程中都一個副本,然而應用程序的全局變量是被所有線程所共享的。當多個線程對這個全局變量進行訪問時,將可能出現很多未知的問題,Win32提供了一種稱爲線程局部存儲的方式,它能使你在第一個運行的線程中創建一個全局變量的拷貝。Delphi利用關鍵字threadvar封裝此功能。在threadvar關鍵字下你可以聲明任何局部存儲的變量。
4、全局變量,多線程最讓人頭疼的地方就是全局變量了,好的同步方式將決定你高效、安全的訪問全局變量,雖然上述的threadvar是解決全局變量線程局部存儲的一個辦法,但在我實際的編碼工作中,幾乎很少用它,它的局限性太多。多線程訪問全局變量的方法將在下一文中詳細描述。
注:轉載請著名出處,謝謝!
線程中的變量
由于每個線程都代表了一個不同的執行路徑,因此,最好有一種只限于一個線程內部使用的數據,
要實現上述目的有以下幾種方式:
1、局部變量(基于棧),很簡單,在你的線程函數中你定義的變量既是如此。由于每個線程都在各自的棧中,各個線程將都有一套局部變量的副本,這樣,就不會相互影響。對于那些只在過程或函數的生存期有意義的變量,應當把它們聲明爲局部變量。
2、存儲在線程對象中。還記得CreateThread函數中的lpParameter參數嗎,它可以接受一個無類型的指針。結合本文第一章的內容,你應該還記得,它被存儲在線程內核對象的上下文結構中,你可以通過CONTEXT結構中的CONTEXT_INTEGER部分的ebx來讀取它的地址。
下面是一段示例代碼,用來演示讀取CONTEXT結構,這段代碼一般用不到,但它可以說明CrateThread函數中的lpParameter被存儲的位置
[url=/bbs/detail_566836.html][img]http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockStart.gif[/img][/url][url=/bbs/detail_566836.html][img]http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ContractedBlock.gif[/img][/url]...{
[url=/bbs/detail_566836.html][img]http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif[/img][/url] 作者:wudi_1982
[url=/bbs/detail_566836.html][img]http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif[/img][/url] 聯系方式:wudi_1982@hotmail.com
[url=/bbs/detail_566836.html][img]http://images.csdn.net/syntaxhighlighting/OutliningIndicators/InBlock.gif[/img][/url] 轉載請著名出處,本代碼爲演示代碼,只貼出了一些關鍵部分
[url=/bbs/detail_566836.html][img]http://images.csdn.net/syntaxhighlighting/OutliningIndicators/ExpandedBlockEnd.gif[/img][/url]}
[url=/bbs/detail_566836.html][img]http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif[/img][/url]
[url=/bbs/detail_566836.html][img]http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif[/img][/url]type
[url=/bbs/detail_566836.html][img]http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif[/img][/url] //傳遞給線程函數的結構和指針的聲明
[url=/bbs/detail_566836.html][img]http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif[/img][/url] Tinfo = record
[url=/bbs/detail_566836.html][img]http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif[/img][/url] count : integer;
[url=/bbs/detail_566836.html][img]http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif[/img][/url] x : integer;
[url=/bbs/detail_566836.html][img]http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif[/img][/url] y : integer;
[url=/bbs/detail_566836.html][img]http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif[/img][/url] end;
[url=/bbs/detail_566836.html][img]http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif[/img][/url] Pinfo= ^Tinfo;
[url=/bbs/detail_566836.html][img]http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif[/img][/url]
[url=/bbs/detail_566836.html][img]http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif[/img][/url]var
[url=/bbs/detail_566836.html][img]http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif[/img][/url]MyThreadHad : THandle;//一個全局變量,用來保存線程的句柄
[url=/bbs/detail_566836.html][img]http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif[/img][/url]
[url=/bbs/detail_566836.html][img]http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif[/img][/url]//線程函數
[url=/bbs/detail_566836.html][img]http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif[/img][/url]function MyThread(info : Pointer):DWORD; stdcall;
[url=/bbs/detail_566836.html][img]http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif[/img][/url]var
[url=/bbs/detail_566836.html][img]http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif[/img][/url] i : integer;
[url=/bbs/detail_566836.html][img]http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif[/img][/url]begin
[url=/bbs/detail_566836.html][img]http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif[/img][/url] //根據傳遞來信息決定在窗口的那個位置輸出什麽信息
[url=/bbs/detail_566836.html][img]http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif[/img][/url] for i := 0 to Pinfo(info)^.count-1 do
[url=/bbs/detail_566836.html][img]http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif[/img][/url] Form1.Image1.Canvas.TextOut(Pinfo(info)^.x,Pinfo(info)^.y,inttostr(i));
[url=/bbs/detail_566836.html][img]http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif[/img][/url] //FreeMem(info);
[url=/bbs/detail_566836.html][img]http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif[/img][/url] Result := 0;
[url=/bbs/detail_566836.html][img]http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif[/img][/url]end;
[url=/bbs/detail_566836.html][img]http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif[/img][/url]
[url=/bbs/detail_566836.html][img]http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif[/img][/url]//創建一個線程
[url=/bbs/detail_566836.html][img]http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif[/img][/url]procedure TForm1.Button4Click(Sender: TObject);
[url=/bbs/detail_566836.html][img]http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif[/img][/url]var
[url=/bbs/detail_566836.html][img]http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif[/img][/url] ppi : Pinfo;
[url=/bbs/detail_566836.html][img]http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif[/img][/url] MyThreadId : DWORD;
[url=/bbs/detail_566836.html][img]http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif[/img][/url]begin
[url=/bbs/detail_566836.html][img]http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif[/img][/url] //分配空間並賦初值
[url=/bbs/detail_566836.html][img]http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif[/img][/url] ppi :=AllocMem(sizeof(tinfo));
[url=/bbs/detail_566836.html][img]http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif[/img][/url] ppi^.count := 1000000;
[url=/bbs/detail_566836.html][img]http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif[/img][/url] ppi^.x := 10;
[url=/bbs/detail_566836.html][img]http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif[/img][/url] ppi^.y := 10;
[url=/bbs/detail_566836.html][img]http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif[/img][/url] //創建
[url=/bbs/detail_566836.html][img]http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif[/img][/url] MyThreadHad := CreateThread(nil,0,@MyThread,ppi,CREATE_SUSPENDED,MyThreadId);
[url=/bbs/detail_566836.html][img]http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif[/img][/url] //在窗體上顯示線程函數的地址和傳遞給它的參數的地址
[url=/bbs/detail_566836.html][img]http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif[/img][/url] labThreadAddr.Caption := inttostr( integer(@MyThread));
[url=/bbs/detail_566836.html][img]http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif[/img][/url] labThreadPvparam.Caption := inttostr(integer(ppi));
[url=/bbs/detail_566836.html][img]http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif[/img][/url]end;
[url=/bbs/detail_566836.html][img]http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif[/img][/url]
[url=/bbs/detail_566836.html][img]http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif[/img][/url]//讀取CONTEXT結構,注意CONTEXT結構是和CPU有關的,我這裏測試時,工作在intel的CPU上
[url=/bbs/detail_566836.html][img]http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif[/img][/url]procedure TForm1.btnRContextClick(Sender: TObject);
[url=/bbs/detail_566836.html][img]http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif[/img][/url]var
[url=/bbs/detail_566836.html][img]http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif[/img][/url] con : _CONTEXT;
[url=/bbs/detail_566836.html][img]http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif[/img][/url]begin
[url=/bbs/detail_566836.html][img]http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif[/img][/url] //初始化結構
[url=/bbs/detail_566836.html][img]http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif[/img][/url] con.ContextFlags := CONTEXT_FULL;
[url=/bbs/detail_566836.html][img]http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif[/img][/url] //讀取
[url=/bbs/detail_566836.html][img]http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif[/img][/url] GetThreadContext(MyThreadHad,con);
[url=/bbs/detail_566836.html][img]http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif[/img][/url] //顯示在窗體的listbox上
[url=/bbs/detail_566836.html][img]http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif[/img][/url] with lbxContextInfo.Items do
[url=/bbs/detail_566836.html][img]http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif[/img][/url] begin
[url=/bbs/detail_566836.html][img]http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif[/img][/url] // Clear;
[url=/bbs/detail_566836.html][img]http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif[/img][/url] Add('------------CONTEXT--------------');
[url=/bbs/detail_566836.html][img]http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif[/img][/url] Add('');
[url=/bbs/detail_566836.html][img]http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif[/img][/url] Add('CONTEXT_DEBUG_REGISTERS-----');
[url=/bbs/detail_566836.html][img]http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif[/img][/url] Add('dr0:'+#9+IntToStr(con.Dr0));
[url=/bbs/detail_566836.html][img]http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif[/img][/url] Add('dr1:'+#9+IntToStr(con.Dr1));
[url=/bbs/detail_566836.html][img]http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif[/img][/url] Add('dr2:'+#9+IntToStr(con.Dr2));
[url=/bbs/detail_566836.html][img]http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif[/img][/url] Add('dr3:'+#9+IntToStr(con.Dr3));
[url=/bbs/detail_566836.html][img]http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif[/img][/url] Add('dr6:'+#9+IntToStr(con.Dr6));
[url=/bbs/detail_566836.html][img]http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif[/img][/url] Add('dr7:'+#9+IntToStr(con.Dr7));
[url=/bbs/detail_566836.html][img]http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif[/img][/url] add('CONTEXT_SEGMENTS---------');
[url=/bbs/detail_566836.html][img]http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif[/img][/url] Add('segGs:'+#9+inttostr(con.SegGs));
[url=/bbs/detail_566836.html][img]http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif[/img][/url] Add('segFs:'+#9+inttostr(con.Segfs));
[url=/bbs/detail_566836.html][img]http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif[/img][/url] Add('segEs:'+#9+inttostr(con.Seges));
[url=/bbs/detail_566836.html][img]http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif[/img][/url] Add('segDs:'+#9+inttostr(con.Segds));
[url=/bbs/detail_566836.html][img]http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif[/img][/url] Add('CONTEXT_INTEGER.---------');
[url=/bbs/detail_566836.html][img]http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif[/img][/url] Add('edi: '+#9+IntToStr(con.Edi));
[url=/bbs/detail_566836.html][img]http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif[/img][/url] Add('esi: '+#9+IntToStr(con.Esi));
[url=/bbs/detail_566836.html][img]http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif[/img][/url] Add('ebx: '+#9+IntToStr(con.Ebx));
[url=/bbs/detail_566836.html][img]http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif[/img][/url] Add('edx: '+#9+IntToStr(con.Edx));
[url=/bbs/detail_566836.html][img]http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif[/img][/url] Add('ecx: '+#9+IntToStr(con.Ecx));
[url=/bbs/detail_566836.html][img]http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif[/img][/url] Add('eax: '+#9+IntToStr(con.Eax));
[url=/bbs/detail_566836.html][img]http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif[/img][/url] Add('CONTEXT_CONTROL----------');
[url=/bbs/detail_566836.html][img]http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif[/img][/url] Add('Ebp: '+#9+IntToStr(con.Ebp));
[url=/bbs/detail_566836.html][img]http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif[/img][/url] Add('Eip: '+#9+IntToStr(con.Eip));
[url=/bbs/detail_566836.html][img]http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif[/img][/url] Add('segcs: '+#9+IntToStr(con.SegCs));
[url=/bbs/detail_566836.html][img]http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif[/img][/url] Add('EFlags: '+#9+IntToStr(con.EFlags));
[url=/bbs/detail_566836.html][img]http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif[/img][/url] Add('Esp: '+#9+IntToStr(con.Esp));
[url=/bbs/detail_566836.html][img]http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif[/img][/url] Add('SegSs: '+#9+IntToStr(con.SegSs));
[url=/bbs/detail_566836.html][img]http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif[/img][/url] end;
[url=/bbs/detail_566836.html][img]http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif[/img][/url]
[url=/bbs/detail_566836.html][img]http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif[/img][/url]end;
[url=/bbs/detail_566836.html][img]http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif[/img][/url]
[url=/bbs/detail_566836.html][img]http://images.csdn.net/syntaxhighlighting/OutliningIndicators/None.gif[/img][/url]
把上面代碼整理之後,添加到你的程序中,你可以發現(如果也是intel的CPU),那麽你可以從Eax寄存器讀取到線程函數的地址,從Ebx中讀取到傳遞給線程函數的參數地址。
在DELPHI中的TThread對象的構造函數中,你可以看到這段代碼
FHandle := BeginThread(nil, 0, @ThreadProc, Pointer(Self), CREATE_SUSPENDED, FThreadID);
再觀察BeginThread的實現,你會發現TThread的調用CreateThread時,將Pointer(Self),也就是TThread對象本身當作線程函數的參數傳遞過去,換言之,你在TThread的派生類中定義的變量,對于一個線程而言,將存儲在這個線程單獨的堆棧中,而它在堆棧的地址存儲在線程的上下文結構中。
可以做一個簡單的試驗,將一個線程生成多次,你可以發現存儲在線程對象內部的變量將互不影響。
說到這裏,必須談論一個問題,效率的問題,我在一本書上曾經看到過這樣一段話“由于訪問線程對象中的數據比訪問線程局部變量要快10倍,因此,你應當盡可能地把線程專用的信息保存在線程對象中。”對此,我一直沒有特別理解。如果一定要相信這句話,那我會這麽理解,就是存儲在線程對象中的變量因爲上下文結構記錄了它的地址等原因,所以它更快。盡信書不如無書,我還在思考,不過好在這種速度的影響對于通常的使用而言影響不大。
3、在DELPHI中,用Object Pascal的關鍵字threadvar來聲明變量,以利用操作系統級的線程局部存儲。
在前面我們了解到:雖然對于局部變量,在每個線程中都一個副本,然而應用程序的全局變量是被所有線程所共享的。當多個線程對這個全局變量進行訪問時,將可能出現很多未知的問題,Win32提供了一種稱爲線程局部存儲的方式,它能使你在第一個運行的線程中創建一個全局變量的拷貝。Delphi利用關鍵字threadvar封裝此功能。在threadvar關鍵字下你可以聲明任何局部存儲的變量。
4、全局變量,多線程最讓人頭疼的地方就是全局變量了,好的同步方式將決定你高效、安全的訪問全局變量,雖然上述的threadvar是解決全局變量線程局部存儲的一個辦法,但在我實際的編碼工作中,幾乎很少用它,它的局限性太多。多線程訪問全局變量的方法將在下一文中詳細描述。
注:轉載請著名出處,謝謝!