線程 - 基於 Perl 解釋器的線程
本文件描述了線程版本 2.36
Perl 提供的“基於解釋器的線程”並非人們可能期望或希望的快速、輕量級的多任務系統。線程的實現方式使它們容易被誤用。很少有人知道如何正確使用它們,或者能夠提供幫助。
在 perl 中使用基於解釋器的線程官方上是不鼓勵的。
use threads ('yield',
'stack_size' => 64*4096,
'exit' => 'threads_only',
'stringify');
sub start_thread {
my @args = @_;
print('Thread started: ', join(' ', @args), "\n");
}
my $thr = threads->create('start_thread', 'argument');
$thr->join();
threads->create(sub { print("I am a thread\n"); })->join();
my $thr2 = async { foreach (@files) { ... } };
$thr2->join();
if (my $err = $thr2->error()) {
warn("Thread error: $err\n");
}
# Invoke thread in list context (implicit) so it can return a list
my ($thr) = threads->create(sub { return (qw/a b c/); });
# or specify list context explicitly
my $thr = threads->create({'context' => 'list'},
sub { return (qw/a b c/); });
my @results = $thr->join();
$thr->detach();
# Get a thread's object
$thr = threads->self();
$thr = threads->object($tid);
# Get a thread's ID
$tid = threads->tid();
$tid = $thr->tid();
$tid = "$thr";
# Give other threads a chance to run
threads->yield();
yield();
# Lists of non-detached threads
my @threads = threads->list();
my $thread_count = threads->list();
my @running = threads->list(threads::running);
my @joinable = threads->list(threads::joinable);
# Test thread objects
if ($thr1 == $thr2) {
...
}
# Manage thread stack size
$stack_size = threads->get_stack_size();
$old_size = threads->set_stack_size(32*4096);
# Create a thread with a specific context and stack size
my $thr = threads->create({ 'context' => 'list',
'stack_size' => 32*4096,
'exit' => 'thread_only' },
\&foo);
# Get thread's context
my $wantarray = $thr->wantarray();
# Check thread's state
if ($thr->is_running()) {
sleep(1);
}
if ($thr->is_joinable()) {
$thr->join();
}
# Send a signal to a thread
$thr->kill('SIGUSR1');
# Exit a thread
threads->exit();
自 Perl 5.8 開始,可以使用稱為解釋器線程的模型進行線程編程,這為每個線程提供了一個新的 Perl 解釋器,並且默認情況下不共享任何數據或狀態信息。
(在 Perl 5.8 之前,可以通過 Thread.pm
API 使用 5005threads。該線程模型已被棄用,並在 Perl 5.10.0 中被移除。)
正如剛才提到的,默認情況下所有變量都是線程本地的。要
use threads;
use threads::shared;
在載入 threads::shared 時,您必須先 use threads
再使用 use threads::shared
。(如果反過來執行,threads
會發出警告。)
強烈建議您在腳本中盡早通過 use threads
啟用線程。
如有需要,腳本可以撰寫成可在多線程和非多線程 Perl 上運行。
my $can_use_threads = eval 'use threads; 1';
if ($can_use_threads) {
# Do processing using threads
...
} else {
# Do it without using threads
...
}
這將創建一個新的線程,該線程將從指定的入口函數開始執行,並將 ARGS 列表作為參數。它將返回相應的線程對象,如果線程創建失敗則返回 undef
。
FUNCTION 可以是函數名稱、匿名子例程或代碼引用。
my $thr = threads->create('func_name', ...);
# or
my $thr = threads->create(sub { ... }, ...);
# or
my $thr = threads->create(\&func, ...);
->new()
方法是 ->create()
的別名。
這將等待相應的線程完成執行。當線程結束時,->join()
將返回入口函數的返回值。
返回值的上下文(void、scalar 或 list)由線程創建時的上下文確定。
# Create thread in list context (implicit)
my ($thr1) = threads->create(sub {
my @results = qw(a b c);
return (@results);
});
# or (explicit)
my $thr1 = threads->create({'context' => 'list'},
sub {
my @results = qw(a b c);
return (@results);
});
# Retrieve list results from thread
my @res1 = $thr1->join();
# Create thread in scalar context (implicit)
my $thr2 = threads->create(sub {
my $result = 42;
return ($result);
});
# Retrieve scalar result from thread
my $res2 = $thr2->join();
# Create a thread in void context (explicit)
my $thr3 = threads->create({'void' => 1},
sub { print("Hello, world\n"); });
# Join the thread in void context (i.e., no return value)
$thr3->join();
更多詳情請參見 "THREAD CONTEXT"。
如果程序退出時仍有未加入或分離的所有線程,則將發出警告。
對已加入的線程調用 ->join()
或 ->detach()
將導致錯誤。
使線程無法加入,並導致任何最終返回值被丟棄。當程序退出時,任何仍在運行的分離線程將被靜默終止。
如果程序退出時仍有未加入或分離的所有線程,則將發出警告。
對已分離的線程調用 ->join()
或 ->detach()
將導致錯誤。
允許線程自行分離的類方法。
允許線程獲取自己的 threads 對象的類方法。
返回線程的 ID。線程 ID 是唯一的整數,程序中的主線程為 0,每創建一個線程增加 1。
允許線程獲取自己的 ID 的類方法。
如果您在use threads
聲明中添加stringify
導入選項,則在字符串或字符串上下文(例如,作為哈希鍵)中使用線程對象將導致其ID用作值
use threads qw(stringify);
my $thr = threads->create(...);
print("Thread $thr started\n"); # Prints: Thread 1 started
這將返回與指定線程ID關聯的活動線程的$tid
是當前線程的值,則此調用的工作方式與->self()
相同。否則,如果沒有與TID關聯的線程,如果線程已加入或分離,如果未指定TID或指定的TID為未定義,則返回undef
。
這是對操作系統的建議,以讓此線程將CPU時間讓給其他線程。實際發生的事情高度依賴於底層線程實現。
您可以執行use threads qw(yield)
,然後在您的代碼中使用yield()
。
沒有參數(或使用threads::all
)並且在列表上下文中,返回所有未加入、未分離的
使用真參數(使用threads::running
),返回所有仍在運行的未加入、未分離的
使用假參數(使用threads::joinable
),返回所有已完成運行的未加入、未分離的->join()
將不會阻塞)。
測試兩個線程對象是否為相同的線程。這被重載為更自然的形式
if ($thr1 == $thr2) {
print("Threads are the same\n");
}
# or
if ($thr1 != $thr2) {
print("Threads differ\n");
}
(線程比較基於線程ID。)
async
創建一個線程來執行其後立即的區塊。此區塊被視為匿名子例程,因此必須在大括號後有一個分號。與threads->create()
一樣,async
返回一個
執行緒在 eval
上下文中執行。如果執行緒正常終止,此方法將返回 undef
。否則,它將返回與執行緒執行狀態中的 $@
相關聯的值,該值位於其 eval
上下文中。
此 私有 方法返回一個指標(即,表示為無符號整數的記憶體位置)到與執行緒物件相關聯的內部執行緒結構。對於 Win32,這是一個指向由 CreateThread
返回的 HANDLE
值的指標(即,HANDLE *
);對於其他平台,這是一個指向在 pthread_create
調用中使用的 pthread_t
結構的指標(即,pthread_t *
)。
此方法對於一般的 Perl 執行緒編程沒有用處。其意圖是為其他(基於 XS 的)執行緒模組提供訪問並可能操作與 Perl 執行緒相關聯的底層執行緒結構的能力。
允許執行緒獲取其自身的 handle 的類方法。
終止執行緒的常見方法是從進入點函數中使用適當的返回值(s) return()。
如果需要,可以隨時通過調用 threads->exit()
來退出執行緒。這將導致執行緒在標量上下文中返回 undef
,或在列表上下文中返回空列表。
當從 主 執行緒調用時,這與 exit(0)
的行為相同。
當從執行緒中調用時,此行為與 threads->exit()
相同(即,退出狀態代碼被忽略)。
當從 主 執行緒調用時,這與 exit(status)
的行為相同。
在執行緒中調用 die()
表示執行緒的異常退出。執行緒中的任何 $SIG{__DIE__}
處理程序將首先被調用,然後執行緒將以包含在 die()
調用中傳遞的任何參數的警告消息退出。
在線程內調用 exit() 會導致整個應用程序終止。因此,在線程代碼內使用 exit()
,或者在可能用於多線程應用程序的模塊中使用它,是強烈不推薦的。
如果真的需要 exit()
,請考慮使用以下方式:
threads->exit() if threads->can('exit'); # Thread friendly
exit(status);
這將全局覆蓋在線程內調用 exit()
的默認行為,並有效地導致此類調用的行為與 threads->exit()
相同。換句話說,在此設置下,調用 exit()
只會導致線程終止。
由於其全局效果,此設置不應在模塊或類似的地方使用。
主 線程不受此設置的影響。
這將僅在新創建的線程內覆蓋 exit()
的默認行為。
這可用於在創建線程後更改線程的 僅退出線程 行為。對於 true 參數,exit()
將僅導致線程退出。對於 false 參數,exit()
將終止應用程序。
主 線程不受此調用的影響。
在線程內部使用的類方法,用於更改其自身對 exit()
的行為。
主 線程不受此調用的影響。
以下布爾方法有助於確定線程的 狀態。
如果線程仍在運行(即,其入口點函數尚未完成或退出),則返回 true。
如果線程已經運行完畢,且未分離且尚未加入,則返回 true。換句話說,線程準備好加入,調用 $thr->join()
將不會 阻塞。
如果線程已分離,則返回 true。
用於允許線程確定自己是否已分離的類方法。
與子程序一樣,線程的入口點函數返回的值的類型可能由線程的 上下文 確定:列表、標量或空。線程的上下文在線程創建時確定。這是必要的,以便上下文通過 wantarray() 可用於入口點函數。然後,線程可以指定適當類型的值,從 ->join()
返回。
因為執行緒的建立和執行緒的加入可能發生在不同的情境下,所以明確地向執行緒的入口函式指定情境可能是有利的。這可以通過將哈希參考作為第一個參數呼叫->create()
來完成。
my $thr = threads->create({'context' => 'list'}, \&foo);
...
my @results = $thr->join();
在上述情況下,執行緒物件以純量情境傳回給父執行緒,並且執行緒的入口函式foo
將以串列(陣列)情境被呼叫,以便父執行緒可以從->join()
呼叫中接收到一個串列(陣列)。 ('array'
同義於 'list'
。)
同樣地,如果您需要執行緒物件,但您的執行緒不會返回值(即無回傳值的情境),您可以執行以下操作
my $thr = threads->create({'context' => 'void'}, \&foo);
...
$thr->join();
情境類型也可以作為哈希參考中的鍵,後跟一個true值。
threads->create({'scalar' => 1}, \&foo);
...
my ($thr) = threads->list();
my $result = $thr->join();
如果沒有明確指定,則執行緒的情境將從->create()
呼叫的情境中隱含。
# Create thread in list context
my ($thr) = threads->create(...);
# Create thread in scalar context
my $thr = threads->create(...);
# Create thread in void context
threads->create(...);
這將以與wantarray()相同的方式返回執行緒的情境。
類方法用於返回當前執行緒的情境。這將返回與當前執行緒的入口函式中運行wantarray()相同的值。
不同平台的每個執行緒的默認堆疊大小差異很大,幾乎總是遠遠超出大多數應用程式的需求。在Win32上,Perl的makefile明確將默認堆疊設置為16 MB;在大多數其他平台上,使用系統默認值,這可能比實際需要的要大得多。
通過調整堆疊大小以更準確地反映應用程式的需求,您可以顯著減少應用程式的內存使用量,並增加同時運行的執行緒數量。
請注意,在Windows上,地址空間分配的粒度為64 KB,因此,在Win32 Perl上將堆疊設置得比這更小將不會節省更多內存。
返回當前每個執行緒的默認堆疊大小。默認值為零,這意味著當前使用系統默認堆疊大小。
返回特定线程的堆栈大小。返回值为零表示系统使用了线程的系统默认堆栈大小。
设置新的每个线程的默认堆栈大小,并返回先前的设置。
某些平台具有最小线程堆栈大小。试图将堆栈大小设置为低于此值将导致警告,并使用最小堆栈大小。
某些Linux平台具有最大堆栈大小。设置过大的堆栈大小将导致线程创建失败。
如果需要,$new_size
将被四舍五入到下一个内存页大小的倍数(通常为 4096 或 8192)。
在设置堆栈大小后创建的线程将调用 pthread_attr_setstacksize()
(对于 pthreads 平台),或者将堆栈大小提供给 CreateThread()
(对于 Win32 Perl)。
(显然,此调用不会影响任何当前存在的线程。)
这在应用程序启动时设置默认的每个线程的堆栈大小。
可以通过使用环境变量 PERL5_ITHREADS_STACK_SIZE
在应用程序启动时设置默认的每个线程的堆栈大小。
PERL5_ITHREADS_STACK_SIZE=1048576
export PERL5_ITHREADS_STACK_SIZE
perl -e'use threads; print(threads->get_stack_size(), "\n")'
此值将覆盖任何给定给 use threads
的 stack_size
参数。它的主要目的是允许为传统线程应用程序设置每个线程的堆栈大小。
要为任何单个线程指定特定的堆栈大小,请使用哈希引用作为第一个参数调用 ->create()
。
my $thr = threads->create({'stack_size' => 32*4096},
\&foo, @args);
这将创建一个新线程($thr2
),该线程继承自现有线程($thr1
)的堆栈大小。这相当于以下简写形式
my $stack_size = $thr1->get_stack_size();
my $thr2 = threads->create({'stack_size' => $stack_size},
FUNCTION, ARGS);
当启用安全信号时(默认行为 - 有关更多详细信息,请参阅"不安全信号"),则信号可以被单个线程发送和处理。
將指定的訊號發送到執行緒。訊號名稱和(正)訊號編號與kill()支援的相同。例如,'SIGTERM','TERM'和(依賴於作業系統)15都是->kill()
的有效參數。
返回執行緒物件以允許方法鏈接
$thr->kill('SIG...')->join();
預期的訊號需要在執行緒中設置訊號處理程序才能作用於它們。以下是一個用於取消執行緒的示例
use threads;
sub thr_func
{
# Thread 'cancellation' signal handler
$SIG{'KILL'} = sub { threads->exit(); };
...
}
# Create a thread
my $thr = threads->create('thr_func');
...
# Signal the thread to terminate, and then detach
# it so that it will get cleaned up automatically
$thr->kill('KILL')->detach();
這是另一個簡單的示例,說明了執行緒訊號與信號量一起使用以提供基本暫停和恢復功能
use threads;
use Thread::Semaphore;
sub thr_func
{
my $sema = shift;
# Thread 'suspend/resume' signal handler
$SIG{'STOP'} = sub {
$sema->down(); # Thread suspended
$sema->up(); # Thread resumes
};
...
}
# Create a semaphore and pass it to a thread
my $sema = Thread::Semaphore->new();
my $thr = threads->create('thr_func', $sema);
# Suspend the thread
$sema->down();
$thr->kill('STOP');
...
# Allow the thread to continue
$sema->up();
注意:此模組提供的執行緒訊號功能實際上並不通過作業系統發送訊號。它在Perl級別模擬訊號,使得訊號處理程序在適當的執行緒中被呼叫。例如,發送$thr->kill('STOP')
並不實際暫停執行緒(或整個進程),但會在該執行緒中調用$SIG{'STOP'}
處理程序(如上所示)。
因此,通常不適合在kill()
命令中使用的訊號(例如,kill('KILL', $$)
)可以與->kill()
方法一起使用(再次,如上所示)。
相應地,向執行緒發送訊號不會干擾執行緒當前正在進行的操作:該訊號將在當前操作完成後執行。例如,如果執行緒在I/O呼叫上阻塞,則向其發送訊號不會導致I/O呼叫被立即中斷以使訊號立即執行。
向已終止/完成的執行緒發送訊號將被忽略。
如果程式退出時還有未加入或分離的執行緒,則會發出此警告。
注意:如果主執行緒退出,則無法使用no warnings 'threads';
來抑制此警告,如下所建議。
查看適當的man頁面以確定失敗的實際原因。
某些執行緒以其他方式終止,而不僅僅是從其進入點函數返回,或者使用 threads->exit()
。例如,執行緒可能因為錯誤而終止,或者使用 die
。
某些平台有最小的執行緒堆疊大小。嘗試將堆疊大小設置為低於此值將導致上述警告,並將堆疊大小設置為最小值。
指定的 SIZE 超過了系統的最大堆疊大小。請使用較小的值作為堆疊大小。
如果需要,可以通過在適當的範圍內使用
no warnings 'threads';
來抑制執行緒警告。
您嘗試使用的特定 Perl 副本未使用 useithreads
配置選項構建。
支持線程需要重新構建 Perl 的所有部分以及 Perl 安裝中的所有 XS 模塊;這不僅僅是添加 threads 模塊的問題(即,線程化和非線程化的 Perl 是二進制不兼容的)。
當前現有執行緒的堆疊大小無法更改,因此,以下操作導致上述錯誤
$thr->set_stack_size($size);
必須啟用安全信號才能使用 ->kill()
信號方法。有關更多詳情,請參見 "Unsafe signals"。
您嘗試使用的特定 Perl 副本不支持在 ->kill()
調用中使用指定的信號。
在考慮提交錯誤報告之前,請諮詢並可能在討論區發布消息,以查看您遇到的問題是否是已知問題。
在創建可能在線程應用程序中使用的模塊時,特別是如果這些模塊使用非 Perl 數據或 XS 代碼,請參見 "在 perlmod 中使您的模塊線程安全"。
不幸的是,您可能會遇到一些不是 線程安全 的 Perl 模塊。例如,它們可能會在執行期間使 Perl 解釋器崩潰,或者在終止時導致核心轉儲。根據模塊和應用程序的要求,可能可以解決這些困難。
如果該模組只會在線程內使用,您可以嘗試在線程入口函數內使用 require
(如果需要,也使用 import
)載入模組。
sub thr_func
{
require Unsafe::Module
# Unsafe::Module->import(...);
....
}
如果該模組需要在主線程內使用,請嘗試修改應用程序,以便在啟動任何線程之後載入模組(同樣使用 require
和 ->import()
),並且確保之後不再啟動其他線程。
如果以上方法無法解決問題,或者對您的應用程序不足以應對,請在 https://rt.cpan.org/Public/ 上對有問題的模組提交 bug 報告。
在大多數系統上,頻繁創建和銷毀線程可能導致 Perl 解釋器的內存占用不斷增加。雖然只需啟動線程然後 ->join()
或 ->detach()
它們很簡單,但對於長期運行的應用程序,最好維護一個線程池,並且使用 隊列 來通知線程待處理的工作。此模組的 CPAN 分發中包含一個簡單的示例(examples/pool_reuse.pl),演示了創建、使用和監控可重用線程池。
在除了 MSWin32 以外的所有平台上,當前工作目錄的設置在所有線程之間共享,因此在一個線程中更改它(例如,使用 chdir()
)將影響應用程序中的所有線程。
在 MSWin32 上,每個線程都維護自己的當前工作目錄設置。
在 Perl 5.28 之前,由於各種競爭條件,無法在線程中使用區域設置。從該版本開始,在實現了線程安全區域函數的系統上,可以使用線程,但存在一些注意事項。這包括從 Visual Studio 2005 開始的 Windows,以及與 POSIX 2008 兼容的系統。請參閱 perllocale 中的"多線程操作"。
每個線程(除了主線程)都是使用 C 區域啟動的。主線程像所有其他 Perl 程序一樣啟動;請參閱 perllocale 中的"ENVIRONMENT"。您可以在任何線程中隨時切換區域設置。
如果要繼承父線程的區域設置,您可以在父線程中設置一個變量,如下所示
$foo = POSIX::setlocale(LC_ALL, NULL);
然後傳遞給 threads->create() 一個閉包 $foo
。然後,在子線程中,您可以這樣說
POSIX::setlocale(LC_ALL, $foo);
或者您可以使用 threads::shared 中的設施來傳遞 $foo
; 或者如果環境沒有改變,在子程序中執行以下操作
POSIX::setlocale(LC_ALL, "");
目前,在除了 MSWin32 以外的所有平台上,從線程中進行的所有 系統 調用(例如使用 system()
或反引號)都使用主線程的環境變數設置。換句話說,在線程中對 %ENV
所做的更改將不會在該線程中進行的 系統 調用中可見。
要解決這個問題,請將環境變數設置為 系統 調用的一部分。例如
my $msg = 'hello';
system("FOO=$msg; echo \$FOO"); # Outputs 'hello' to STDOUT
在 MSWin32 上,每個線程都維護自己的一套環境變數。
信號由腳本的主線程(線程 ID = 0)捕獲。因此,在線程中設置信號處理程序,除了文檔中上述的 "線程信號" 目的外,將不會實現預期的效果。
如果試圖在線程中捕獲 SIGALRM
,則要處理線程中的警報,請在主線程中設置信號處理程序,然後使用 "線程信號" 將信號中繼到該線程
# Create thread with a task that may time out
my $thr = threads->create(sub {
threads->yield();
eval {
$SIG{ALRM} = sub { die("Timeout\n"); };
alarm(10);
... # Do work here
alarm(0);
};
if ($@ =~ /Timeout/) {
warn("Task in thread timed out\n");
}
};
# Set signal handler to relay SIGALRM to thread
$SIG{ALRM} = sub { $thr->kill('ALRM') };
... # Main thread continues working
在某些平台上,可能無法在仍有現有 子 線程的情況下銷毀 父 線程。
自 Perl 5.8.0 起,Perl 中的信號已經通過將其處理延遲到解釋器處於 安全 狀態時,使其更安全。有關更多詳細信息,請參見 "perl58delta 中的安全信號" 和 "perlipc 中的延遲信號(安全信號)"。
安全信號是默認行為,舊的、立即的、不安全的信號行為僅在以下情況下生效
Perl 已構建有 PERL_OLD_SIGNALS
(請參見 perl -V
)。
環境變數 PERL_SIGNALS
被設置為 unsafe
(請參見 "perlrun 中的 PERL_SIGNALS")。
使用模塊 Perl::Unsafe::Signals。
如果不安全的信號生效,則信號處理不是線程安全的,並且無法使用 ->kill()
信號方法。
當通過join
操作從線程返回值時,該值及其引用的所有內容將被複製到加入的線程中,方式與在創建線程時複製值的方式類似。對於大多數類型的值,包括數組、哈希和子例程,這都可以正常工作。複製會遞歸地遍歷數組元素、引用純量、被子例程閉包的變數和其他類型的引用。
然而,返回值引用的所有內容在加入的線程中都是全新的複本,即使返回的物件在子線程中是從父線程中的某個東西複製而來。加入後,父線程將因此擁有每個這樣物件的副本。這有時會很重要,特別是如果該物件被改變了;這對於返回的子例程提供訪問權限的私有數據尤其重要。
從線程返回被祝福的物件是行不通的。根據所涉及的類別,您可以通過返回物件的序列化版本(例如使用Data::Dumper或Storable),然後在加入的線程中重新構造它來解決此問題。如果您使用的是 Perl 5.10.0 或更高版本,並且如果該類別支持共享物件,則可以通過共享隊列傳遞它們。
可以通過使用require或eval與適當的程式碼將END區塊添加到線程中。這些END
區塊將在線程的解釋器被銷毀時執行(即在->join()
呼叫期間或程式結束時)。
然而,在這樣的END
區塊中調用任何threads方法很可能會失敗(例如,應用可能會掛起,或產生錯誤),因為需要控制threads模組內部功能的互斥鎖。
因此,強烈建議不要在線程中使用END
區塊。
在 Perl 5.14 及更高版本中,在不支持fchdir
C 函式的 Windows 系統之外的系統上,目錄句柄(參見opendir)將不會被複製到新線程中。您可以使用Config.pm中的d_fchdir
變數來確定您的系統是否支持它。
在之前的 Perl 版本中,使用打開目錄處理的線程會導致解釋器崩潰。[perl #75154]
如果主線程在仍在運行的分離線程存在時退出,那麼 Perl 的全域銷毀階段將不會被執行,因為否則在分離線程被銷毀之前可能會摧毀控制線程操作並且在主線程的記憶體中分配的某些全域結構。
如果您正在使用需要執行全域銷毀階段進行清理(例如,刪除臨時文件)的任何代碼,則不要使用分離線程,而是在退出程序之前加入所有線程。
對線程的支援超出了此模塊中的代碼(即 threads.pm 和 threads.xs),並且擴展到 Perl 解釋器本身。舊版本的 Perl 包含可能在使用來自 CPAN 的最新版本 threads 時仍可能出現的錯誤。除了升級到 Perl 的最新版本外,沒有其他解決方法。
即使使用最新版本的 Perl,也已知某些與線程相關的構造可能會導致有關洩漏純量或未引用純量的警告消息。但是,此類警告是無害的,可以安全地忽略。
您可以在 threads 相關的 bug 報告中搜索:https://rt.cpan.org/Public/。如果需要,請將任何新 bug、問題、補丁等提交至:https://rt.cpan.org/Public/Dist/Display.html?Name=threads
Perl 5.8.0 或更高版本
在 MetaCPAN 上的 threads: https://metacpan.org/release/threads
CPAN 發行版的代碼存儲庫: https://github.com/Dual-Life/threads
https://www.perl.com/pub/a/2002/06/11/threads.html 和 https://www.perl.com/pub/a/2002/09/04/threads.html
Perl 線程郵件列表:https://lists.perl.org/list/ithreads.html
堆棧大小討論:https://www.perlmonks.org/?node_id=532956
CPAN 上此發行版的 examples 目錄中的示例代碼。
Artur Bergman <sky AT crucially DOT net>
Jerry D. Hedden <jdhedden AT cpan DOT org>製作的CPAN版本
threads以與Perl相同的許可證發行。
Richard Soderberg <perl AT crystalflame DOT net> - 在尋找競爭條件和其他奇怪的錯誤原因方面給予我大量幫助!
Simon Cozens <simon AT brecon DOT co DOT uk> - 答覆無數討厭的問題時一直在那裡
Rocco Caputo <troc AT netrus DOT net>
Vipul Ved Prakash <mail AT vipul DOT net> - 幫助進行調試
Dean Arnold <darnold AT presicient DOT com> - 堆棧大小API