歴史的背景
スレッドは、Perlにおける並行計算やマルチタスクプログラムのリソースを同時に扱う必要性に応じて登場しました。標準化されたスレッドモジュールは、Perl 5.8以降安定して搭載され、ithreadsから汎用のthreads::sharedへと徐々に進化しました。
問題点
最初の難しさは、PerlがJavaのようにネイティブでスレッドをサポートしていないことです。Perlにおけるスレッドは、各スレッドのスタックとデータをコピーすることで機能し、オーバーヘッドを生じ、(threads::sharedを介した特別なバインディングの変数を除いて)グローバル変数への直接操作が不可能になります。また、Perlは明示的な同期なしにデータに同時に書き込む際、スレッドが独立して動作することを保証しません。
解決策
スレッドを構成するために、threadsモジュールとスレッド間でデータを交換するための追加モジュールthreads::sharedを使用します。データの同期と一貫性の確保は、開発者の責任であり、多くの場合、ロックを使用して行われます。
コード例:
use threads; use threads::shared; my $counter :shared = 0; sub increment { lock($counter); $counter++; } my @threads; for (1..10) { push @threads, threads->create(\&increment); } $_->join for @threads; print "Counter: $counter ";
主な特徴:
スレッドが相互に変化を見ることを期待して、threads::sharedを使わずに任意のグローバル変数を使用することは可能ですか?
いいえ。グローバル変数は各スレッドに個別にコピーされます。データの交換にはthreads::sharedまたは他のIPCを使用する必要があります。
Perlの同じスクリプト内でforkとthreadsを同時に実行することは許可されていますか?
forkとthreadsを混合することは推奨されていません。これにより予測不可能なバグや不安定な動作が生じるためです。Perlはこれらの手法を同時に使用することについて公式に警告しています。
標準的な参照を介してスレッド間で複雑なデータ構造を転送することは可能ですか?
いいえ。Perlは再帰的にネストされた構造を自動的にコピーしないため、そのような試みはエラーや直感に反する結果を招きます。これには深いコピーと共有リソースの使用が必要です。
開発者が配列を使用して簡単なキューを作成しましたが、threads::sharedを介さずに複数のスレッドから同時に更新されました。その結果、データが頻繁に壊れ、プログラムの実行結果が不正確になりました。
メリット:
デメリット:
ロックを使用してthreads::sharedを利用し、全キューが共有として宣言され、同期がロックを介して行われました。プログラムは高負荷時でも安定して動作しました。
メリット:
デメリット: