14

(および)のよう<defunct>に表示されるプロセスがいくつかあります。私は実際のスクリプトとプログラムから物事を煮詰めました。topps

私の中で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)ははるかに簡単に変更することができます。

4

6 に答える 6

14

彼らはwait(2)システムコールの対象ではなかったからです。

誰かが将来これらのプロセスを待つ可能性があるため、カーネルはそれらを完全に取り除くことができwaitないか、終了ステータスまたはその存在の証拠がなくなるため、システムコールを実行できなくなります。

シェルから1つを開始すると、シェルはSIGCHLDをトラップし、とにかくさまざまな待機操作を実行しているため、長い間機能しなくなるものはありません。

ただし、cronは待機状態ではなく、スリープ状態になっているため、cronがウェイクアップするまで、機能しなくなった子がしばらくの間立ち往生する可能性があります。


更新:   コメントへの返信...うーん。私はなんとか問題を複製することができました:

 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フォークとcron子がシェルを開始します
  • シェル(1636)はsidとpgid 1636を開始し、スリープを開始します
  • シェルが終了し、SIGCHLDがcron3562に送信されました
  • 信号が無視されるか、誤って処理されます
  • シェルはゾンビになります。スリープはinitに再ペアレント化されるため、スリープが終了すると、initはシグナルを取得してクリーンアップすることに注意してください。私はまだゾンビがいつ刈り取られるかを理解しようとしています。おそらくアクティブな子がいない場合、cron 1629はそれが終了できることを理解し、その時点でゾンビは初期化して刈り取られるように親になります。だから今、cronが処理すべきであったSIGCHLDが欠落しているのではないかと思います。
    • 必ずしもvixiecronのせいではありません。ここでわかるように、libdaemonはのdaemon_fork()にSIGCHLDハンドラーをインストールします。これは、中間1629までのクイック出口でのシグナル配信を妨げる可能性があります。

      今では、Ubuntuシステムのvixie cronがlibdaemonで構築されているかどうかさえわかりませんが、少なくとも新しい理論があります。:-)

于 2009-10-01T22:48:58.893 に答える
8

私の意見では、これは、crontabのコマンドのstdout /stderrにパイプされるstdinへの入力を待機しているプロセスCROND(すべてのタスクに対してcrondによって生成される)が原因です。これは、cronが結果の出力をメールでユーザーに送信できるために行われます。

したがって、CRONDは、ユーザーコマンドと、生成されたすべての子プロセスがパイプを閉じるまでEOFを待機します。これが行われると、CRONDは待機ステートメントを続行し、その後、無効なユーザーコマンドが消えます。

したがって、スクリプト内で生成されたすべてのサブプロセスをパイプから明示的に切断する必要があると思います(たとえば、ファイルまたは/ dev /nullにリダイレクトすることによって)。

したがって、次の行はcrontabで機能するはずです。

* * * * * ( /tmp/launcher.sh /tmp/tester.sh &>/dev/null & ) 
于 2014-03-25T16:29:33.930 に答える
4

cronはセッション内のすべてのサブプロセスが終了するのを待っていると思われます。負のpid引数については、wait(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とsleepが同じSESSにあることに注意してください。

コマンドsetsid(1)を使用します。tester.shは次のとおりです。

#!/bin/bash
setsid sleep 27 # the real script launches a compiled C program in the background

必要ないこと&に注意してください。setsidはそれをバックグラウンドに配置します。

于 2009-10-01T23:29:25.093 に答える
3

2つの別々のプロセスを持たないことで、問題を解決することをお勧めします。launcher.sh最後の行でこれを実行します。

exec "$@"

これにより、余分なプロセスが排除されます。

于 2009-10-01T23:00:16.863 に答える
2

同様の問題の解決策を探していたときに、この質問を見つけました。残念ながら、この質問の答えは私の問題を解決しませんでした。

親プロセスを見つけて強制終了する必要があるため、無効なプロセスを強制終了することはできません。私は次の方法で機能しなくなったプロセスを強制終了しました。

ps -ef | grep '<defunct>' | grep -v grep | awk '{print "kill -9 ",$3}' | sh

"grep''"では、検索対象を特定の無効なプロセスに絞り込むことができます。

于 2011-10-22T00:42:04.783 に答える
-3

私は同じ問題を何度もテストしました。そして最後に私は解決策を手に入れました。以下に示すように、bashスクリプトの前に「/ bin/bash」を指定するだけです。

* * * * * / bin / bash /tmp/launcher.sh /tmp/tester.sh
于 2012-03-21T02:52:47.333 に答える