Thread とは?実行の単位
thread は scheduler が管理する最小の実行単位です。プロセス内で動き、そのプロセスのメモリを共有する命令のシーケンスです。
プログラムはプロセスとして動き、そのプロセス内で 1 つ以上の thread が作業を行います。各 thread は独自の call stack を持ち、独自の命令シーケンスを実行しますが、プロセス内のすべての thread は同じ heap とグローバルメモリを共有します。その共有メモリが thread の調整を安価にし、同時に並行性のバグの源にもなります。
thread とは何か
thread は、独自の stack とプログラムカウンタを持つ独立した実行経路で、プロセス内に存在します。オペレーティングシステムは thread を CPU コアにスケジュールし、それらを切り替えて複数の thread を進めます。
thread とプロセス
プロセスは独自のメモリを持つ分離されたプログラムです。thread はプロセス内で動き、そのメモリを兄弟 thread と共有します。thread は作成が軽く、通信が速いですが、1 つの thread のバグがすべての thread の共有状態を破壊しうります。
thread が共有するものとしないもの
- 共有: heap メモリ、グローバル変数、開いているファイル、address space。
- プライベート: 各 thread 独自の call stack とレジスタ。
- 共有状態こそ、thread 間の高速な通信を可能にするものです。
- 共有状態はまた、race と deadlock を可能にするものでもあります。
thread のコスト
thread はプロセスより安価ですが無料ではありません。それぞれが stack を持ち、OS はそれらを切り替えるのに時間を使います。何千もの thread を spawn するとメモリを使い果たしたり scheduler を酷使したりしえます。だからこそ多くのシステムは thread pool を使います。
簡単な例
test runner は worker thread の pool を使って多くのテストファイルを一度に実行し、各 worker thread が共有キューから次のファイルを引き出す、といったことができます。
CI における thread
thread の多い test run は小さな runner のコアとメモリを飽和させ、遅くなったり OOM に達したりしえます。より大きな runner(Latchkey)は thread に動かす本物のコアを与え、thread やメモリのスパイクによる一時的な OOM kill は自動 retry できます。
重要なポイント
- thread はプロセス内で動く、スケジュール可能な最小の実行単位です。
- thread は heap とグローバルを共有しますが、各々が独自の stack を持ちます。
- 共有メモリは thread の調整を高速にしますが、race と deadlock を可能にします。