差分

移動先: 案内検索

プロセス管理

1,831 バイト除去, 2019年1月7日 (月) 10:37
/* プロセスの基本的概念 */
プログラムが動作する実行実体のことをプロセスと呼びます。
単純化して説明すると、プログラムの実行のことです。
 
プロセスはプロセスごとにプロセスIDを付与され、その数字で管理されています。
このプロセスIDの数字は[[プロセスIDを擬似乱数生成関数の初期化パラメータに使う是非 | 一定の数字で循環]]します。
Linuxカーネルが扱えるプロセスIDの最大値は/proc/sys/kernel/pid_maxを参照すればわかりますが、
一般向けのLinuxディストリビューションであれば現状ではプロセスIDの最大値は 2^15 (32768) となっています。
 
 
それで説明が終わるのはあんまりなので、もうちょっと概念的にどのような位置づけなのか考えてみます。
スレッドやタスクの考え方(と、実装)は80年代にUNIXに入って来た、UNIXの歴史から見ると、わりと新しい技術です。
80年代に入ってから色々な組織がスレッドの実装を試みました。
Brown Univ米ブラウン大学の [https://cs.のブラウンスレッド、brown.edu/research/pubs/techreports/reports/CS-96-18.html Brown Thread Package (BTP)]、サンマイクロシステムズのLWP (Lightweiht ProcessLight-weight process)、DECのCMA スレッド、、DECのDECthreads、
CMUのCスレッドパッケージがありました。各々互換性はありません。
紆余曲折あり、現在ではPOSIX仕様のスレッドである[http://man7.org/linux/man-pages/man7/pthreads.7.html pthreads(7)]が主流になっています。
ですから、単純にプロセスと呼んでも構わないですし、
また同時に(ここまでの説明の範囲では)「プロセス=タスクのこと」と考えてもかまいません。
タスクは複数のスレッドを持つことができます。複数のスレッドが動き出すまでは、プロセスといってもいいわけですが、スレッドを複数持つ状態の場合は、プロセスと呼ぶよりタスクと呼ぶ方が適切でしょう。タスクは複数のスレッドを持つことができます。複数のスレッドが動き出すまでは、プロセスといってもいいわけですが、スレッドを複数持つ状態の場合は、プロセスと呼ぶよりタスクと呼ぶ方が適切でしょう。
このあたりは新旧の考え方が入り乱れて呼び方が混乱しているのは確かなようです。
UNIXが生まれた当時の処理の粒度と今時のUNIXでの処理の粒度は違うので、
;調べてみよう: コマンドuptimeのマニュアルを調べてみよう。またロードアベレージの意味も調べてみよう。コマンド[http://man7.org/linux/man-pages/man1/uptime.1.html uptime]のマニュアルを調べてみよう。またロードアベレージの意味も調べてみよう。
=== プロセスの状態 ===
親プロセスが子プロセスを生むという形を取り、子プロセスは親プロセスのコピーとして動き始めます。例外はすべてのプロセスの始まりであるinitだけです。
;調べてみよう: コマンドpstreeを使って、すべてのプロセスの親子関係がどうなっているかチェックしてみよう。コマンド [http://man7.org/linux/man-pages/man1/pstree.1.html pstree]を使って、すべてのプロセスの親子関係がどうなっているかチェックしてみよう([[pstreeの出力例]])。
==== fork(2) ====
スレッドは計算資源を共有しCPU資源だけは別の状態であるような処理の流れをいいます。スレッドにはclone(2)のようなカーネルレベルで実行するスレッドとglibcなどユーザライブラリに含まれているユーザレベルで実行するスレッドの2つがあります。ですからスレッドが必ずしもカーネルモードで動作しているわけではなく、それはプログラムの書かれ方によります。ここの説明ではカーネルスレッドとユーザスレッドとの両方取り上げてみます。
 
 
既に説明した通りfork(2)が親と子のプロセスで内容をコピーしているのですが、とはいえ fork(2) 後は各々の実体は独立しています。しかし、スレッドは内容が一緒ですから、つまり処理の流れを別に持つCPU資源だけは複数個持つのですから、新しいプロセスが生まれていないので親も子もありません。CPU資源以外の計算資源のコピーが必要ない場合、あるいは同じ計算資源でCPU 資源を複数持ちたい時、計算資源を共有したい時などにスレッドは便利です。
 
 
CPUリソースだけを同時に複数個持つことができることで、たとえば実行しているタスク中でネットワーク入出力からの処理を行いつつ同時に他の計算を繰り返すような場合に非常に有効に働きができます。
この利点は、資源コピーが発生しないまま処理スレッドだけを高速に立ち上げることができると説明しましたが実際にfork(2)とLinuxのpthreadライブラリ(カーネルスレッドではなくユーザスレッド)を使ってどれぐらい違うか試してみました。
1000 回プロセスを生成するのとスレッドを生成するプログラムを書いてみます。結果はAthlon 1GHzマシンでスレッド生成側がトータル0.157秒、プロセス生成側が0.360秒と2倍以上の差をつけました。このようにCPUリソースのみだけで処理が出来るようなものを大量に生成するような場合はスレッドが有利に働きます。
 
 
生成可能な最大スレッド数は利用しているシステムのメモリ量に依存します。/proc/sys/kernel/threads-max を参照することでわかります。
* fork版
[[マルチプロセッサとプロセス]]へ移動しました。
 
=== マルチプロセッサとスレッド ===
 
スレッド単位で割り当てる場合、実行中プログラムの持つ複数のスレッドが複数のCPUに同時に割り当てられていきます。その場合はプログラムの処理のスピードは CPU 単体の最大処理速度を越えることが可能になります。ただ、それでも上手にスレッドを分割し、その処理タイミングをきちんとプログラミングできる場合という前提が満たされることが必要です。
 
[[File:CodeCogsEqn-2.png|thumb|left|250px|こんな計算を仮定してみる。]]
例えば、配列 A = { a1, a2, a3, ... an }があって、表の値をすべて掛けたものを、表の値をすべて足したもので割るという計算をしたいとしましょう。
 
まず、a1 * a2 * a3 * ... * anを計算しAに代入するスレッドとa1 + a2 + a3+ ... + anを計算しBに代入するスレッドを作ります。両方のスレッドの計算の終了を待ってA/Bを計算します。この時、各々のスレッドが別々のCPUで並列に動くので1個のCPUで全部を計算させるよりも速く計算
<ref>マルチスレッドを使い円周率を計算したプログラム例: https://uc2.h2np.net/src/mt-bbp.c </ref>
ができるはずです。
 
しかしこの場合、処理効率が単純に2倍に上がるわけではありません。たとえば1CPUでの計算に20秒かかったとしましょう。2CPU を使い分母、分子の計算が分割でき並列に計算されたとしても、もし、分子の計算が12秒かかり、分母の計算が10秒かかり、分子÷分母の計算が0.5秒かかったならば、分母の計算時間と割り算の時間を足したものがクリティカルパスですから、その処理時間は12.5秒となります。このようにCPU数が増えたからといって単純に性能がCPU数に合わせて倍数的に増えていくわけではありませんし、もちろん処理が並列化されていないプログラムをいくら走らせても当然ながらその結果はCPUを1つ占有出来ること以上の効果はありません。
 
;調べよう: 並列処理一般において処理効率には上限があることを示しているのがアムダールの法則です。アムダールの法則について調べてみましょう。<ref>ジーン・アムダールが書いた1967年の論文 "[http://www-inst.eecs.berkeley.edu/~n252/paper/Amdahl.pdf http://www-inst.eecs.berkeley.edu/~n252/paper/Amdahl.pdf]" が公開されています。ここに書かれている並列計算の遅滞に関する内容が後にアムダールの法則と呼ばれるようになります。</ref>
=== 脚注 ===