なぜクロンによって生まれたプロセスが廃止されるのですか?
-
19-09-2019 - |
質問
私にはいくつかのプロセスが表示されます <defunct>
の top
(と ps
)。実際のスクリプトやプログラムから物事を煮詰めました。
私の中で crontab
:
* * * * * /tmp/launcher.sh /tmp/tester.sh
の内容 launcher.sh
(もちろん実行可能とマークされています):
#!/bin/bash
# the real script does a little argument processing here
"$@"
の内容 tester.sh
(もちろん実行可能とマークされています):
#!/bin/bash
sleep 27 & # the real script launches a compiled C program in the background
ps
以下を示します:
user 24257 24256 0 18:32 ? 00:00:00 [launcher.sh] <defunct>
user 24259 1 0 18:32 ? 00:00:00 sleep 27
ご了承ください tester.sh
表示されません - バックグラウンドジョブを起動した後に終了しました。
なぜ launcher.sh
マークされたマーク <defunct>
?それは、によって開始されたときにのみこれを行うようです cron
- 自分で実行したときではありません。
追加メモ: launcher.sh
これが実行されるシステム内の一般的なスクリプトであり、簡単に変更できません。他のこと(crontab
, tester.sh
, 、私がその代わりに実行するプログラムでさえ sleep
)はるかに簡単に修正できます。
解決
彼らはaの主題ではなかったからです wait(2)
システムコール。
誰かが将来これらのプロセスを待つかもしれないので、カーネルはそれらを完全に取り除くことができないか、それが実行することができません wait
システムコールは、その存在の出口ステータスや証拠がもうないためです。
シェルから1つを開始すると、シェルはシグルドを閉じ込めていて、とにかくさまざまな待機操作を行っているので、長い間廃止されたままではありません。
しかし、クロンは待機状態にないので、眠っているので、障害のある子供は、クロンが目を覚ますまでしばらくの間固執するかもしれません。
アップデート: コメントに応答する...うーん。私は問題を複製することができました:
PPID PID PGID SESS COMMAND
1 3562 3562 3562 cron
3562 1629 3562 3562 \_ cron
1629 1636 1636 1636 \_ sh <defunct>
1 1639 1636 1636 sleep
だから、何が起こったのか、私は思う:
- Cron ForksとCron Childがシェルを開始します
- シェル(1636)はSIDとPGID 1636を開始し、睡眠を開始します
- シェルが出て、sigchldはcron 3562に送られました
- 信号は無視されるか、誤っています
- シェルはゾンビになります。睡眠はinitに補償されているため、睡眠が出ると、initが信号を取得してクリーンアップすることに注意してください。私はまだゾンビがいつ得られるかを理解しようとしています。おそらく、アクティブな子供がいない場合は、1629年に出口が出る可能性があると考えています。その時点で、ゾンビはイニシと刈り取られます。だから今、私たちは、Cronが処理すべきだったSigchldが欠けているのではないかと思います。
- 必ずしもビクシークロンのせいではありません。ここで見ることができるように、 LibdaemonはSigchldハンドラーをインストールします その間
daemon_fork()
, 、そして、これは中間1629年のクイックエクスでの信号配信を妨げる可能性があります今、私のUbuntuシステムのVixie CronがLibdaemonで構築されているかどうかさえわかりませんが、少なくとも新しい理論があります。 :-)
- 必ずしもビクシークロンのせいではありません。ここで見ることができるように、 LibdaemonはSigchldハンドラーをインストールします その間
他のヒント
Cronがセッションのすべてのサブプロセスが終了するのを待っているのではないかと思います。否定的なPID引数に関しては、待機(2)を参照してください。あなたは次のようにsessを見ることができます
ps faxo stat,euid,ruid,tty,tpgid,sess,pgrp,ppid,pid,pcpu,comm
これが私が見ているものです(編集):
STAT EUID RUID TT TPGID SESS PGRP PPID PID %CPU COMMAND
Ss 0 0 ? -1 3197 3197 1 3197 0.0 cron
S 0 0 ? -1 3197 3197 3197 18825 0.0 \_ cron
Zs 1000 1000 ? -1 18832 18832 18825 18832 0.0 \_ sh <defunct>
S 1000 1000 ? -1 18832 18832 1 18836 0.0 sleep
SHと睡眠は同じセスにあることに注意してください。
コマンドsetSid(1)を使用します。これがtester.shです:
#!/bin/bash
setsid sleep 27 # the real script launches a compiled C program in the background
必要ないことに注意してください &
, 、Setsidはそれをバックグラウンドに置きます。
私の意見では、それは、クロンタブのコマンドのstdout/stderrにパイプされたstdinでの入力を待っているプロセス・クランド(すべてのタスクのためにrondによって生まれた)によって引き起こされます。これは、Cronがユーザーにメールで結果の出力を送信できるために行われます。
そのため、Crondはユーザーコマンドが発生するまでEOFを待っています。これが行われた場合、Crondは待機ステートメントで続行し、その後、廃止されたユーザーコマンドが消えます。
したがって、私はあなたがあなたのスクリプト形式のすべての生成されたサブプロセスをパイプの形式で明示的に切断する必要があると思います(例えば、それをファイルまたは /dev /nullにリダイレクトすることにより。
したがって、次の行はクロンタブで動作するはずです。
* * * * * ( /tmp/launcher.sh /tmp/tester.sh &>/dev/null & )
2つの別々のプロセスを持たないだけで問題を解決することをお勧めします。 launcher.sh
最後の行でこれを行います:
exec "$@"
これにより、余分なプロセスが排除されます。
同様の問題のある解決策を探している間に、この質問を見つけました。残念ながら、この質問の答えは私の問題を解決しませんでした。
親のプロセスを見つけて殺す必要があるため、廃止プロセスを殺すことは選択肢ではありません。最終的には、次のように廃止プロセスを殺すことになりました。
ps -ef | grep '<defunct>' | grep -v grep | awk '{print "kill -9 ",$3}' | sh
「grep '' "では、検索を絞り込むことができます。
同じ問題を何度もテストしました。そして最後に私は解決策を持っています。以下に示すように、バッシュスクリプトの前に「/bin/bash」を指定するだけです。
* * * * * /bin/bash /tmp/launcher.sh /tmp/tester.sh