はじめに
プロセスとスレッドについて少し勉強したので、まとめてみたいと思います。
勉強のまとめとして書いている記事となります。
間違ったことを書いている可能性があるため、是非別のドキュメントにもあたってご確認いただければと思います。
プロセスとは
プロセスとは「OS 上の処理の最小実行単位」、平たく言えば「動作中のプログラム」のことです。
たとえば、ターミナル上で ls
などの基本的なコマンドを打ったときや、ソフトウェアを起動したときは OS 上では全てプロセスとして実行されます。
自分のコンピューターに存在するプロセスは $ ps ax
で調べることができます。
プロセスの作成
このプロセスを生成する方法は一つしかなく、既存のプロセスを複製(fork)するしかありません。
この複製元のプロセスを「親プロセス」、複製によって新しく作成されたプロセスを「子プロセス」と言います。
OS を起動するとまず init プロセスが起動され、この init プロセスを親として子プロセスを生成し、この子プロセスを親としたプロセスを生成し…というようにしてプロセスを生成していきます。
そのため、全てのプロセスは init プロセスの子孫ということになります。
プロセスは複製された後、プロセスの中身を別のプログラムに丸ごと置き換える(exec)ことができます。
たとえば、「Linux にログインして bash シェル上で ls
コマンドを実行する」際には、以下の順序で ls
コマンドのプロセスが生成されます。
プロセスの一生
プロセスは生成されてから終了するまでに以下の状態を遷移します。
- 休止中
- 実行待ち
- 実行中
OS 上のほとんどのプロセスは普段休止状態です。
そのため、エンジニアが注視すべきなのは「実行中」と「実行待ち」の状態のプロセスです。
「実行待ち」のプロセスとは、実行待ちキューに登録して OS から CPU リソースが割り当てられるのを待っているプロセスのことです。
つまり、処理を実行するためのリソースを OS からもらうために並んでいる状態のプロセスです。
そして実際に CPU リソースを割り当てられたプロセスを「実行中」のプロセスのといいます。
役目を果たしたプロセスが終了すると、一旦ゾンビプロセス(defunct)と言われる状態になります。
その後、このゾンビプロセスの親プロセスが wait()
システムコールを呼び出すことでこのプロセスは消滅します。
プロセスの制御
プロセスの制御は「シグナル」を介して行います。
よくターミナル上で Ctrl + C や Ctrl + Z で何らかの処理を停止させたり一時停止させたりするのも、プロセスにシグナルを送ることで制御しています。
因みに先程、ゾンビプロセスを消滅させる方法はそのプロセスの親プロセスが wait()
システムコールを呼び出すと述べましたが、何らかの理由で親プロセスが wait()
システムコールを呼び出さないと、このゾンビプロセスは残り続けることになります。
この場合は、このゾンビプロセスに対して SIGKILL
というシグナルを送るとゾンビプロセスを消滅させることができる場合があります。
プロセス間通信
プロセス同士は共通のデータを参照したり、更新したりすることはできません。
複数のプロセスで共通のデータを参照・更新したい場合は、プロセス間でデータの受け渡しを行う必要があります。
このプロセス間のデータのやり取りを「プロセス間通信」といいます。
たとえば以下の例では、cat
コマンドのプロセスと grep
コマンドのプロセスでプロセス間通信が行われています。
$ cat /var/log/messages | grep error
スレッドとは
スレッドとは「並列処理を目的としてプロセス内に複数作れるタスクの実行単位」のことです。
プロセスは fork して子プロセスを生成するだけでなく、そのプロセス内にあたかもプロセスのように動作させることができる複数のスレッドを生成することができます。
これらのスレッドの生成はプロセスの fork より処理が軽いため、スレッドは「軽量プロセス」「ライトウェイトプロセス」とも言われます。
スレッドもプロセスと区別なく実行待ちキューに入って実際に実行されます。
さらに同じプロセス内のスレッド同士は、共通のデータを参照・更新をすることができます。
たとえば、ファイルをダウンロードするスレッドとダウンロードの進捗状況をプログレスバーで表示するスレッドでダウンロードの UX を表現することができます。
終わりに
プロセスとスレッドについてまとめました。
勉強中の身なので、間違っている点があれば是非コメントいただけると嬉しいです。