プロセスとスレッド、タスク、ジョブの違いを説明できる人は意外と少ないと思います。
ぼくの経験では、『人と場所』によって微妙に違いました。しかも間違いじゃないので困りものです。
ということで、プロセスとスレッドの違いを(ついでにタスクとジョブも)、『正解』ではなく『間違っていない』ところで説明します。
プロセス - プログラムの実行手順 -
processは英語の授業風に言うと、
経過、進行、手順
ここでは『プログラムの実行の手順』になります。プログラムは、
- メモリがHDD・SDDのプログラムファイルを読み込む
- CPUが、処理するのに必要なメモリ情報を読み込む
- CPUが処理する
- 終わったら、次の処理に必要なメモリを読み込んで処理をつづけるか、処理が終わりならメモリを開放する
の『手順』で処理をします。これが『プロセス』です。
プログラムを実行するためにメモリ上にアップされてから解放されるまでが1プロセスです。
マルチプロセスってなに?
マルチプロセスという言葉を聞いたことがあると思います。
同じ資源(ファイル)を使ってメモリを別々に展開し、それぞれちがうプロセスで処理をすることです。
たとえばメモ帳などのテキストエディタはマルチプロセスです。
同じアイコン(実行ファイル)をクリックしているのに、複数個のエディタウィンドウが開きますよね?
エディタに書き込んだ内容は、ほかのエディタウィンドウに影響しません。
このようにプロセスを同時に実行(並列処理)することをマルチプロセスといいます。
プロセスはメモリに展開して解放されるまでの処理の流れ
マルチプロセスはお互いに干渉しない。
(プロセスの独立)
スレッド - 子プロセス -
プロセスはメモリに展開してCPUに処理をさせますが、その処理の中で新しくプロセスを作ることができます。
これを子プロセスと呼びスレッドともいい、スレッドを起動するプロセスを親プロセスといいます。
threadは英単語では、
糸、筋道、一脈
何かから派生するイメージですね? プロセスから派生したプロセスだからスレッドです。
スレッドもプロセスなので独自のメモリ展開を行います。そして処理が終わるとメモリを開放します(スレッド終了)。
マルチスレッドってなに?
スレッドにもマルチスレッドがあります。マルチプロセスと同じように複数のスレッドを作って並行処理をします。
もちろん、それぞれのスレッドは独立しています。
じつは、スレッドは親プロセスのコピーです。
(メモリーのコピーをつくって新しいプロセスをつくります。)
ただ、
スレッド | 親プロセスのコピーから別プログラムを起動 |
親プロセス | スレッド作成だけ行なって別プログラム起動はしない |
という違いがあり話せば長くなるので、イメージしやすいように省略しました。
共有メモリってなに?
プロセスやスレッドは、共有メモリを使ってデータ共有ができます。
共有メモリはOSのシステムで管理しているメモリ領域で、まったく独立したプロセス間でも、親子のプロセスでも共有できます。
C系言語(C, C++など)を使ったことのある人はスレッドのことを『フォーク(fork)する』と表現します。
fork()関数をコールしてスレッドを作るから。
マルチスレッドのプログラミングが一番理解しやすいのはC系言語です。
スレッドの細かいプログラミングができるので、
メッセージキュー
共有メモリ
セマフォ
といった共有メモリまわりの処理もプログラミングできます。
JavaにはThreadクラスがあります。名前そのままでスレッド処理をします。マルチスレッドも実装できます。
Javaではスレッドを作っているところまではイメージできますが、C系言語ほど細かいプログラミングはしません。
細かいところはThreadクラスに任せてしまうのでスレッドの意味をイメージするのはむずかしいです。
ひとつのスレッドで処理するプログラムをシングルスレッドといいます。JavaScriptやPHPはその代表格。
ただし、いまのJavaScriptやPHPはマルチスレッドの処理を実装することができるので、垣根はなくなっています。
(シングルプロセスともいいます。)
- スレッドはプロセスが作るプロセス
- 子プロセス
共有メモリはOSで管理するメモリ領域なので、サイズが大きいものには向いていません。
(サイズ変更のカスタマイズはできる。)
ぼくの経験では、キャッシュ(ファイル)やデータベースを使ってプロセス間の共有をしたり、パラメータでデータを渡すことが多いです。
(パラメータはスレッドで別プログラムを起動するときに渡すデータのこと。)
プロセスとスレッドのおまけ
プロセスには、
orphan process
(孤児プロセス)
zombie process
(ゾンビプロセス)
があります。Unix, Linuxのプロセス・スレッドの話で、これを外して語れないほどよく出てきます。
孤児プロセスってなに?
プロセスとスレッドで大事なことをいい忘れてました。
親が死んでも子は生きる。
親と子はとても関係が深いですが、あくまでそれぞれ独立しています。
親が亡くなったら悲しいですが、ほとんどの人は自分の人生を頑張って生きるでしょう。
人間と同じですね?
親プロセスが終了しても子プロセスには関係ありません。
しかしプロセスは人とちがって、かならず生きている親をもつことになっています。
プロセスには、親をなくした孤児を預かる孤児院のシスターみたいな、すべてを包み込んでくれるプロセスがいます。
initプロセス
initプロセスは、すべてのプロセスのご先祖様でもあります。
initプロセスが死ぬときは、OSがおかしくなっているかシャットダウンするときなので、すべてのプロセスにはかならず親がいます。
ゾンビプロセスってなに?
ゾンビプロセスは、子プロセスの処理が終わって親プロセスが後片づけするのを待っている状態です。
(親プロセスが子プロセスの終了ステータスを読むのを待つ。)
このとき、子プロセスは処理が終わっているので使っていたメモリはいらないです。
しかし、プロセスの状態を管理するプロセステーブルに情報が残り、別のプロセスが使いたいメモリに割りあてることができません。
プロセステーブルはプロセスが使うメモリの量も管理しているので、プロセスがメモリを使わなくてもメモリ領域だけは確保している。
またプロセスは実行できる数の上限が決まっているので、ゾンビプロセスが増えすぎると新しいプロセスが作れないこともあります。
(プロセスを作るとき、ある程度メモリを使うのでメモリ不足でプロセスが作れない。)
ゾンビプロセスは死んでいるが死亡届が出されていない。
死んでるのに死んでないことになっている = ゾンビ
死んでないことになっているので、メモリが開放されない。
ゾンビプロセスは、ふだんは害はないが、CPUやメモリの負荷が大きくなるとトラブルの原因になる。
親プロセスが子プロセスの終了ステータスを読んだら、プロセステーブルがクリアされます。
(子プロセスのメモリが開放される。)
具体的には親プロセスがwaitpid()やwait()を使い子プロセスの状態を監視します。
C言語の子プロセスの終了ステータスは、main()の戻り値。
一般的に、
正常終了 | 0 |
異常終了 | -1 |
その他 | カスタム |
その他にも決まったコードがあった気がするが忘れた。
ちなみにmainは、プロセス・スレッドのメイン処理という意味。
ゾンビプロセスの生まれる原因
ゾンビプロセスが生まれる原因は、
親の育児放棄。
さっき、『子プロセスの処理が終わったら終了ステータスが読まれるのを待つ』といいました。
その終了ステータスを読むのが親プロセスの仕事です。プロセスでは、
子の尻ぬぐいは親がする
ことになっています。独立心はあるのに最後のシメは親に投げちゃうんですね?
プロセスは超ド級のわがまま甘ちゃんです。親がケツを拭いてくれなかったらゾンビになるんですから。
ゾンビプロセスが出る原因はこれだけ。親がしっかりしてればゾンビになりません。
親プロセスにはwaitの仕事をしっかりさせましょう。ゾンビが生まれるのは親プロセス処理のバグのせいです。
ゾンビプロセスを退治する方法
ゾンビプロセスを片づける方法は、
ゾンビプロセスを孤児プロセスにしてあげる。
親が育児放棄しているので保護してあげるんですね?
その方法は、
親を殺す。
サスペンスです。
親をなくしてしまえば、initプロセスが保護して親になってくれます。
initプロセスは甘えん坊のプロセスの面倒をよくみるので、ケツを拭いてパウダーでポンポンしてくれます。ゾンビになることはありません。
initプロセスは定期的にwaitを実行しています。
また、ゾンビプロセスはすでに死んでいるのでコマンド(kill)で殺せません。
『親を殺す』と言ってしまいましたが、通常は親プロセスを再起動します。
親の心を入れ替えさせてやり直しさせ、過去の過ち(ゾンビ)はぜんぶinitプロセスが引き受けます。
再起動した親プロセスは、手放した子プロセスの面倒を見ることはありません。新しく生まれた子プロセスの面倒を見ます。
タスクとジョブ
最後にタスクとジョブです。これがプロセス・スレッドまわりの混乱の原因です。
task, jobは英単語では、
仕事
タスクは仕事をさらに区切った『作業』というニュアンス。でもコンピュータでは同じような使い方をします。
タスクやジョブの意味はそれぞれのシステムやアプリケーションで違い、
- 1プロセスをタスク or ジョブ
- プロセスの集合体をタスク or ジョブ
- 1スレッドをタスク or ジョブ
- スレッドの集合体をタスク or ジョブ
- プロセスやスレッド内の特定の処理をタスク or ジョブ
と呼んだりします。決まった定義はありません。
人でも『仕事』の定義はあいまいですよね? 国によっても違いますし業界や会社によっても違います。個人でも仕事の考え方は違うでしょう。
Windowsにはタスクマネージャーがありますが、その最初のタブは『プロセス』です。
Windowsではタスクの中に『サービス』や『プロセス』があるイメージです。
タスクとジョブは深く考えない。意味はケースバイケース
まとめ
プロセスとスレッドの違いはありません。スレッドもひとつのプロセスです。
プロセスとスレッドは『違う』というよりも『親子』といったほうがいいかも。
父親も母親も人間、自分も人間ですよね?
ですが、親と自分はぜんぶ同じではありません。クローンじゃないんだから。そんな感じです。
タスクとジョブは『そんなくくりがある』程度でいいです。これ以上考えると混乱します。
ぼくが経験した中では『タスク管理』『ジョブ管理』という、ど直球ど真ん中に名づけられたサブシステムを見たことがあります。しかもまったく違う業界の別のシステム開発で。
(もちろん微妙にタスクとジョブの定義はちがいました。プロセス・スレッドの呼び方も若干ちがいました。)
大きなシステム開発では、機能や役割ごとにサブシステムというものを作って、サブシステムを結合してシステムを作ります。