2

他のプログラムがいつ終了するかを通知するプログラムを作成するにはどうすればよいですか?

4

8 に答える 8

11

自分で作成したものではないプログラムで waitpid() または waitid() を実行する唯一の方法は、そのプログラムを ptrace して親になることです。

以下は、posix オペレーティング システムで ptrace を使用して一時的に別のプロセスの親になり、そのプログラムが終了するまで待機する方法の例です。副作用として、終了コードと、そのプログラムを終了させたシグナルを取得することもできます。

#include <sys/ptrace.h>
#include <errno.h>
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <sys/wait.h>

int main(int argc, char** argv) {

    int pid = atoi(argv[1]);
    int status;
    siginfo_t si;

    switch (ptrace(PTRACE_ATTACH, pid, NULL)) {
        case 0:
            break;
        case -ESRCH:
        case -EPERM:
            return 0;
        default:
            fprintf(stderr, "Failed to attach child\n");
            return 1;
    }
    if (pid != wait(&status)) {
        fprintf(stderr, "wrong wait signal\n");
        return 1;
    }
    if (!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP))  {
        /* The pid might not be running */
        if (!kill(pid, 0)) {
            fprintf(stderr, "SIGSTOP didn't stop child\n");
            return 1;
        } else {
            return 0;
        }
    }
    if (ptrace(PTRACE_CONT, pid, 0, 0)) {
        fprintf(stderr, "Failed to restart child\n");
        return 1;
    }

    while (1) {
        if (waitid(P_PID, pid, &si, WSTOPPED | WEXITED)) {
            // an error occurred.
            if (errno == ECHILD)
                return 0;
            return 1;
        }
        errno = 0;

        if (si.si_code & (CLD_STOPPED | CLD_TRAPPED)) {
            /* If the child gets stopped, we have to PTRACE_CONT it
             * this will happen when the child has a child that exits.
             **/
            if (ptrace(PTRACE_CONT, pid, 1, si.si_status)) {
                if (errno == ENOSYS) {
                    /* Wow, we're stuffed. Stop and return */
                    return 0;
                }
            }
            continue;
        }

        if (si.si_code & (CLD_EXITED | CLD_KILLED | CLD_DUMPED)) {
            return si.si_status;
        }
        // Fall through to exiting.
        return 1;
    }
}
于 2008-09-24T06:28:36.937 に答える
4

Windows で私が使用した手法は、グローバルな名前付きオブジェクト (CreateMutex を使用したミューテックスなど) を作成し、監視プログラムに同じ名前付きミューテックスを開き、(WaitForSingleObject を使用して) 待機させることです。最初のプログラムが終了するとすぐに、2 番目のプログラムはミューテックスを取得し、最初のプログラムが終了したことを認識します。

Unix では、これを解決する通常の方法は、最初のプログラムで pid (getpid()) をファイルに書き込むことです。2 番目のプログラムは、(kill(pid, 0) を使用して) この pid を監視して、最初のプログラムがまだ終了しているかどうかを確認できます。この方法は競合状態の影響を受けやすく、間違いなくそれを解決するためのより良い方法があります。

于 2008-09-24T06:22:11.790 に答える
4

別のプロセスを生成し、実行中に何もしない場合、ほとんどの高水準言語には、これを行うための組み込み機能が既に用意されています。たとえば、Perl では、systemプロセスを実行して終了を待つための と バックティックの両方があり、 IPC::System::Simpleなどのモジュールを使用して、プログラムがどのように終了したか、また、あなたが喜んでいるか悲しんでいるかを簡単に把握できます。それが起こったことについて。すべてを処理する言語機能を使用することは、自分でやろうとするよりもはるかに簡単です

Unix フレーバーのシステムを使用している場合、フォークしたプロセスが終了すると、SIGCHLD シグナルが生成されます。これは、子プロセスが実行している他のことをプログラムが実行できることを意味します。

SIGCHLD シグナルのキャッチは、言語によって異なります。Perl では、次のようにシグナル ハンドラを設定します。

use POSIX qw(:sys_wait_h);

sub child_handler {

    while ((my $child = waitpid(-1, WNOHANG)) > 0) {
         # We've caught a process dying, its PID is now in $child.
         # The exit value and other information is in $?
    }

    $SIG{CHLD} \&child_handler;  # SysV systems clear handlers when called,
                                 # so we need to re-instate it.
}

# This establishes our handler.
$SIG{CHLD} = \&child_handler;

CPAN には、上記のサンプル コードよりも優れた機能を果たすモジュールがほぼ確実に存在します。waitpid特定のプロセス ID (すべてに -1 ではなく) を使用できますWNOHANG。他のプロセスが完了するまでプログラムをスリープさせたい場合は使用しません。

シグナル ハンドラーの内部にいる間は、あらゆる種類の奇妙なことが発生する可能性があることに注意してください。別のシグナルが入ってくる可能性があり (そのため、while ループを使用してすべてのデッド プロセスをキャッチします)、言語によっては、別の操作の途中である可能性があります。

Windows で Perl を使用している場合は、Win32::Processモジュールを使用してプロセスを生成->Waitし、結果のオブジェクトを呼び出してプロセスが終了するのを待つことができます。のすべての内臓に精通しているわけではありませんが、プロセスがまだ停止しているかどうかを確認するには、 の長さ(または1 ミリ秒)Win32::Process待つことができるはずです。01

他の言語や環境では、走行距離が異なる場合があります。他のプロセスが停止したときに、それがどのように停止するかを確認してください。ユーザーがサブプロセスを強制終了したためにサブプロセスを終了させるには、通常、タスクが正常に終了したために終了する場合とは異なる応答が必要です。

ではごきげんよう、

ポール

于 2008-09-24T06:41:27.513 に答える
2

Windowsを使用していますか?もしそうなら、以下は問題を解決するはずです-あなたはプロセスIDを渡す必要があります:

  bool WaitForProcessExit( DWORD _dwPID )
  { 
     HANDLE hProc = NULL;
     bool bReturn = false;

     hProc = OpenProcess(SYNCHRONIZE, FALSE, _dwPID);

     if(hProc != NULL)
     {
       if ( WAIT_OBJECT_0 == WaitForSingleObject(hProc, INFINITE) )
       {
         bReturn = true;
       }
     }

     CloseHandle(hProc) ;
  }

  return bReturn;
}

注:これはブロッキング機能です。非ブロッキングが必要な場合は、INFINITEを小さい値に変更し、ループで呼び出す必要があります(同じPIDの別のプロセスで再度開かないように、おそらくhProcハンドルを開いたままにします)。

また、私はこのソースコードをテストする時間がありませんでしたが、動作する私のアプリからそれを持ち上げました。

于 2008-09-24T07:56:41.297 に答える
0

ほとんどのオペレーティングシステムは、一般的に同じ種類のものです....

問題のプログラムのプロセスIDを記録し、アクティブなプロセスを定期的に照会して監視するだけです

少なくともウィンドウでは、イベントをトリガーしてそれを行うことができます...

于 2008-09-24T06:25:35.213 に答える
-2

うーん、できません。これは、その性質上、不可能な作業です。

別のプログラム foo-sub を入力として受け取るプログラム foo があるとします。

Foo {
 func Stops(foo_sub) { run foo_sub; return 1; }
}

これの問題点は、かなり単純な設計であっても、foo-sub が決して終わらないプログラムである場合、foo 自体が終わらないということです。foo-sub と foo のどちらがプログラムを停止させているのか、プログラムの実行に 1 世紀かかるかどうかを決定する要因を外部から判断する方法はありません。

本質的に、これはコンピューターが答えられない質問の 1 つです。より完全な概要については、Wikipedia にthisに関する記事があります。

于 2008-09-24T06:28:45.423 に答える
-3

これは「停止問題」と呼ばれ、解決できません。http://en.wikipedia.org/wiki/Halting_problemを参照してください。

于 2008-09-24T06:18:35.010 に答える
-3

実行せずに1つのプログラムを分析したい場合、それは解決できない問題です。

于 2008-09-24T06:21:02.120 に答える