ログアウトした後もプロセスがまだ実行されているのはなぜですか?

ログアウトした後もプロセスがまだ実行されているのはなぜですか?

からログインした後ssh、 で次のコマンドを入力しますbash:

sleep 50000000000000 &

次に、プロセスの親プロセス (つまり ) を切断しますkill -9sleepその後bash、ターミナル ウィンドウが同時に切断されます。

再度ログインすると、sleepプロセスがまだ実行されていることがわかります。

質問:sleepログアウトしてターミナルを閉じてもプロセスが存続できるのはなぜですか? 私の考えでは、デーモンとnohupプログラム以外はすべてログアウト中に終了するはずです。sleepこのように存続できる場合、コマンドの代わりにこの方法を使用できるということですかnohup?

答え1

要約:

sleepログアウトしてターミナルを閉じてもプロセスが存続できるのはなぜですか? 私の考えでは、デーモンとnohupプログラム以外はすべてログアウト中に終了するはずです。sleepこのように存続できる場合、コマンドの代わりにこの方法を使用できるということですかnohup?

bashによって生成されたインスタンスにsshオプションが設定されていない限りhuponexit、終了/ログアウト時にプロセスが終了されることはありません。また、huponexitオプションが設定されている場合、kill -9シェルで を使用することはnohup、シェルの子プロセスで を使用することの代わりとしては適切ではありません。nohupシェルの子プロセスで を使用すると、シェルからではない SIGHUP から子プロセスが保護されます。また、それが重要でない場合でも、nohupシェルを正常に終了できるため、 を使用することをお勧めします。


bashは というオプションがありhuponexit、これを設定すると、bash終了/ログアウト時に子プロセスが SIGHUP されるようになります。

インタラクティブ非ログイン bashインスタンス、たとえばbashによって生成されたインスタンスではgnome-terminal、このオプションは無視されます。huponexitが設定されているかどうかに関係なく、bashの子はbash終了時に によって SIGHUP されることはありません。

インタラクティブログイン bashインスタンス、たとえばbashによって生成されたインスタンスではssh、このオプションは無視されません (ただし、デフォルトでは設定されていません)。 がhuponexit設定されている場合、bashの子はbash終了/ログアウト時にによって SIGHUP されます。huponexitが設定されていない場合、bashの子は終了/ログアウト時に によって SIGHUP されませんbash

したがって、一般に、オプションが設定されてbashいない限りhuponexit、対話型ログイン インスタンスを終了/ログアウトしても、シェルは子に対して SIGHUP を実行しません。また、対話型非ログインbashインスタンスを終了/ログアウトしても、シェルは子に対して SIGHUP を実行しません。

しかし、この場合はこれは無関係です。 を使用すると、親プロセス( )を終了しても、後者が実行する機会が残らないkill -9 sleepため、いずれにせよ存続します。bash何でも前者(つまり、現在のbashインスタンスがログインbashインスタンスであり、huponexitオプションが設定されている場合は、SIGHUP する)に変更します。

これに加えて、他のシグナル( に送信される SIGHUP シグナルなどbash)とは異なり、 SIGKILL シグナルはプロセスの子プロセスに伝播されることはなく、したがってsleep強制終了されることもありません。

nohupSIGHUP シグナルの影響を受けないプロセスを開始しますが、これは別のものです。SIGHUP シグナルを受信して​​もプロセスがハングアップするのを防ぎます。この場合、オプションが設定されてシェルが終了しbashた場合、対話型ログイン インスタンスによってこのシグナルが受信される可能性があります。したがって、技術的には、オプションを設定せずに対話型ログイン インスタンスでプロセスを開始すると、SIGHUP シグナルを受信して​​もプロセスがハングアップするのを防ぎますが、シェルを終了/ログアウトしても SIGHUP は行われません。huponexitnohupbashhuponexit

ただし、一般的に、親シェルからの SIGHUP シグナルを防ぐ必要がある場合、子シェルのメソッドよりも親シェルのメソッドnohupを優先する理由はありません。代わりに、その逆を行う必要があります。kill -9nohup

メソッドを使用して親kill -9を終了しても、親が正常に終了する機会は残されませんが、nohupメソッドを使用して子を開始すると、親は SIGHUP ( を使用して開始された子のコンテキストで意味をなす例nohup) などの他のシグナルによって終了され、正常に終了できるようになります。

答え2

bashデフォルトで終了時に子プロセスにHUPシグナルを送信しない. 詳しくは(@kosさんありがとう)、非ログインシェル

bashを設定すると、ログインシェルオプションを設定する場合はhuponexit、ターミナルで次のようにします。

[romano:~] % bash -l

(これにより新しい「ログイン」シェルが起動します)

romano@pern:~$ shopt -s huponexit
romano@pern:~$ sleep 1234 &
[1] 32202
romano@pern:~$ exit
logout

次にsleepプロセスを確認します。

[romano:~] % ps augx | grep sleep
romano   32231  0.0  0.0  16000  2408 pts/11   S+   15:23   0:00 grep sleep

...実行されていません: HUP シグナルを受信し、要求どおりに終了しました。

答え3

この方法で生き残ることができる場合、コマンドsleepの代わりにこのメソッドを使用できることを意味しますか?nohup

kill -9は、本当にやるべき方法ではありません。テレビの電源を切るために銃でテレビを撃つようなものです。コメディ要素以外に利点はありません。プロセスは をキャッチしたり無視したりすることはできませんSIGKILL。プロセスに実行中の処理を終了してクリーンアップする機会を与えないと、破損したファイル (またはその他の状態) が残ってしまい、再起動できなくなります。はkill -9、他に何も機能しない場合の最後の希望です。


ログアウトしてターミナルが閉じられているのに、スリープ プロセスが存続できるのはなぜでしょうか。私の考えでは、デーモンと nohup プログラム以外のすべてがログアウト時に終了されると思います。

あなたの場合は何が起きますか:

の親プロセスはsleep現在実行中のbashシェルです。kill -9その bash を実行すると、bash プロセスはSIGHUP子プロセスに を送信する機会がありません。これは、 SIGKILL( によって送信されるkill -9) がプロセスによってキャッチできないためです。スリープ プロセスは実行を続けます。スリープは、孤立プロセス

init (PID 1) プロセスは、再親付けと呼ばれるメカニズムを実行します。つまり、init プロセスは孤立したプロセスの親になります。init は例外で、元の親プロセスを失ったプロセスを収集するため、プロセスは init の子になることができます。ちなみに、デーモン (などsshd) は「バックグラウンドで実行」するときにこれを実行します。

そうしないと、孤立したプロセスは後で (終了したときに) ゾンビ プロセスになります。これは、がwaitpid()呼び出されない場合に発生します (そのプロセスが強制終了されたときには果たせない親プロセスの責任)。init は、waitpid()ゾンビの子プロセスを回避するために、特定の間隔で呼び出します。

答え4

を使用すると、&プログラムはバックグラウンドで実行されます。バックグラウンドでプログラムを確認するにはbg、コマンド を使用し、再度フォアグラウンドで実行させるには、 を実行しますfg

はい、メインターミナルが終了してもプログラムを実行し続ける方法は多数あります。

関連情報