執行緒 - 處理 Perl 中的執行緒 (僅適用於舊程式碼)
Thread
模組用作舊式執行緒模型 (稱為 5005threads) 的前端,該模型是在 5.005 版中引入的。該模型已棄用,並已在 5.10 版中移除。
對於舊程式碼和臨時向後相容性,Thread
模組已重新設計,以作為新解釋器執行緒 (ithreads) 模型的前端。但是,某些先前的功能不可用。此外,兩個執行緒模型之間的資料共用模型完全不同,任何與資料共用相關的事項都必須以不同的方式思考。使用 ithreads 時,您必須明確在執行緒之間 share()
變數。
強烈建議您盡快將任何現有的執行緒程式碼移轉到新的模型 (即使用 threads
和 threads::shared
模組)。
在 Perl 5.005 中,執行緒模型是所有資料都隱含共用,並且必須明確同步對資料的共用存取。此模型稱為 5005threads。
在 Perl 5.6 中,引入了新的模型,其中所有內容都是執行緒本機,並且必須明確宣告對資料的共用存取。此模型稱為 ithreads,代表「解釋器執行緒」。
在 Perl 5.6 中,ithreads 模型並未作為公開 API 提供;僅作為內部 API,供延伸模組撰寫人員使用,並在 Win32 平台上實作 fork() 模擬。
在 Perl 5.8 中,ithreads 模型透過 threads
模組提供,而 5005threads 模型已棄用。
在 Perl 5.10 中,5005threads 模型已從 Perl 解釋器中移除。
use Thread qw(:DEFAULT async yield);
my $t = Thread->new(\&start_sub, @start_args);
$result = $t->join;
$t->detach;
if ($t->done) {
$t->join;
}
if($t->equal($another_thread)) {
# ...
}
yield();
my $tid = Thread->self->tid;
lock($scalar);
lock(@array);
lock(%hash);
my @list = Thread->list;
Thread
模組為 Perl 提供多執行緒支援。
new
在引用的子常式中啟動執行緒的新執行緒。選用清單作為參數傳遞給子常式。執行會持續在子常式和 new
呼叫後的程式碼中。
Thread->new
回傳一個執行緒物件,代表新建立的執行緒。
lock
在變數上放置鎖定,直到鎖定範圍結束。
如果變數被另一個執行緒鎖定,lock
呼叫會封鎖直到變數可用。lock
是遞迴的,因此可以安全地多次呼叫 lock
--變數會保持鎖定狀態,直到變數最外層的鎖定範圍結束。
變數鎖定只會影響 lock
呼叫--不會 影響對變數的正常存取。(子常式的鎖定不同,稍後會說明。)如果你真的、真的 希望鎖定封鎖存取,那就繼續吧,將它們綁定到某個東西並自行管理。這是故意的。雖然管理變數存取是一件好事,但 Perl 不會強迫你離開它的起居室...
如果容器物件(例如雜湊或陣列)被鎖定,該容器的所有元素都不會被鎖定。例如,如果執行緒執行 lock @a
,任何其他執行緒執行 lock($a[12])
都不會封鎖。
最後,lock
將只會向上追溯參考一個 層級。lock(\$a)
等同於 lock($a)
,而 lock(\\$a)
則不等於。
async
建立一個執行緒來立即執行緊接在它之後的區塊。這個區塊被視為一個匿名子常式,因此在閉合大括號後必須加上分號。就像 Thread->new
,async
會回傳一個執行緒物件。
Thread->self
函式會回傳一個執行緒物件,代表執行 Thread->self
呼叫的執行緒。
傳回所有未加入、未分離的 Thread 物件清單。
cond_wait
函數會將一個已鎖定的變數作為參數,解鎖該變數,並封鎖,直到另一個執行緒對同一個已鎖定變數執行 cond_signal
或 cond_broadcast
為止。cond_wait
封鎖的變數會在 cond_wait
滿足後重新鎖定。如果有多個執行緒在同一個變數上執行 cond_wait
,除了其中一個之外,其他執行緒都會重新封鎖,等待重新取得變數的鎖定。(因此,如果你只使用 cond_wait
進行同步,請盡快放棄鎖定。)
cond_signal
函數會將一個已鎖定的變數作為參數,並解除一個在該變數上執行 cond_wait
的執行緒的封鎖。如果有多個執行緒在該變數上執行 cond_wait
而被封鎖,只會解除其中一個執行緒的封鎖(哪一個執行緒會被解除封鎖是不確定的)。
如果沒有執行緒在該變數上執行 cond_wait
而被封鎖,則會捨棄該訊號。
cond_broadcast
函數的運作方式類似於 cond_signal
。不過,cond_broadcast
會解除在已鎖定變數上執行 cond_wait
而被封鎖的所有執行緒的封鎖,而不只解除一個執行緒的封鎖。
yield
函數允許另一個執行緒取得 CPU 的控制權。確切的結果取決於實作。
join
會等待執行緒結束,並傳回執行緒結束時傳出的任何值。join
會封鎖,直到執行緒結束為止,但如果執行緒已經終止,則不會封鎖。
如果執行 join
的執行緒die
了,則會在此刻傳回執行緒die
時傳出的錯誤。如果你不希望執行 join
的執行緒也die
,則應該將 join
包裝在 eval
中,或使用 eval
執行緒方法,而不是 join
。
detach
會告訴執行緒它永遠不會被加入,也就是說,一旦執行緒停止執行,就可以移除其存在的所有痕跡。分離執行緒中的錯誤不會在任何地方可見 - 如果你想要捕捉這些錯誤,你應該使用 $SIG{__DIE__} 或類似的東西。
equal
會測試兩個執行緒物件是否代表同一個執行緒,如果它們代表同一個執行緒,則傳回 true。
tid
方法會傳回執行緒的 tid。tid 是在建立執行緒時指定的單調遞增整數。程式的主執行緒的 tid 會是零,而後續執行緒的 tid 會從一開始指定。
done
方法會傳回 true,如果你正在檢查的執行緒已完成,否則傳回 false。
以下功能已在 5005threads 中實作,但不再適用於 ithreads。
在 5005threads 中,你也可以 lock
一個子程式,讓來自其他執行緒對該子程式的任何呼叫都會被封鎖,直到鎖定解除。
此外,子程式可以用 :locked
屬性宣告,這會序列化對子程式的存取,但允許不同執行緒非同時存取。
eval
方法會在 join
周圍包住一個 eval
,因此會等待執行緒退出,傳遞執行緒可能傳回的任何值,並將任何錯誤放入 $@
。
flags
方法會傳回執行緒的旗標,一個對應於執行緒內部旗標的整數值。