質問

私にはいくつかのプロセスが表示されます <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で構築されているかどうかさえわかりませんが、少なくとも新しい理論があります。 :-)

他のヒント

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
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top