Как написать программу, которая сообщает, когда закончится моя другая программа?Как написать программу, которая сообщает, когда закончится моя другая программа?
ответ
Это называется «проблема с остановкой» и не разрешима. См. http://en.wikipedia.org/wiki/Halting_problem
Если вы хотите проанализировать одну программу без выполнения, то это проблема неразрешимая.
В Windows, метод, который я использовал, - это создать глобальный именованный объект (такой как мьютекс с CreateMutex), а затем открыть программу мониторинга, которая называется именованным мьютексом, и дождаться ее (с помощью WaitForSingleObject). Как только первая программа выходит, вторая программа получает мьютекс и знает, что первая программа вышла.
В Unix обычный способ решить эту задачу - перенести первую программу pid (getpid()) в файл. Вторая программа может контролировать этот pid (с помощью kill (pid, 0)), чтобы увидеть, исчезла ли первая программа. Этот метод подчиняется условиям гонки, и, несомненно, есть лучшие способы его решения.
Большинство операционных систем его в целом такая же вещь ....
записи идентификатора процесса программы в вопросе и просто следить за ним, запрашивая Actives процессы периодически
В окнах по меньшей мере, , вы можете инициировать события, чтобы сделать это ...
Единственный способ сделать waitpid() или waitid() в программе, которая не порождена самим собой, - стать ее родителем, ptrace'ing ее.
Ниже приведен пример использования ptrace в операционной системе posix, чтобы временно стать родителем процессов, а затем дождаться завершения этой программы. В качестве побочного эффекта вы также можете получить код выхода, и сигнал, который вызвал эту программу для выхода .:
#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;
}
}
Умм вы не можете, это невыполнимая задача, учитывая характер этого.
Предположим, у вас есть программа foo, которая принимает в качестве входной программы другую программу foo-sub.
Foo {
func Stops(foo_sub) { run foo_sub; return 1; }
}
Проблема с этим все это быть довольно упрощенно дизайна является то, что довольно просто, если Foo-югу это программа, которая никогда не заканчивается, сама Foo никогда не заканчивается. Нет никакого способа сказать извне, если foo-sub или foo - это то, что заставляет программу останавливаться, и что определяет, требуется ли вашей программе просто потратить столетие?
По существу, это один из вопросов, на которые компьютер не может ответить. Для более полного обзора в Википедии есть статья о this.
Если вы хотите создать другой процесс и затем ничего не предпринимать во время его запуска, то на большинстве языков более высокого уровня уже есть встроенные модули для этого. Например, в Perl есть как system
, так и обратные линии для запуска процессов и их завершения до завершения, а также такие модули, как IPC::System::Simple, чтобы упростить вычисление того, как программа завершилась, и были ли вы счастливы или грусти о том, что произошло. Использование функции языка, которая обрабатывает все для вас, - это way проще, чем пытаться сделать это самостоятельно.
Если вы используете систему с приложением 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
с определенным идентификатором процесса (а не -1 для всех) и без WNOHANG
, если вы хотите, чтобы ваша программа спала до завершения другого процесса.
Помните, что, находясь внутри обработчика сигнала, могут возникать всевозможные странные вещи. Может появиться другой сигнал (поэтому мы используем цикл while, чтобы поймать все мертвые процессы), и в зависимости от вашего языка вы можете быть частью другой операции!
Если вы используете Perl в Windows, вы можете использовать модуль Win32::Process для запуска процесса и вызвать ->Wait
на результирующем объекте, чтобы дождаться его смерти. Я не знаком со всеми смехами Win32::Process
, но вы должны быть в состоянии дождаться длины 0
(или 1
за одну миллисекунду), чтобы проверить, не закончился ли процесс.
На других языках и условиях ваш пробег может отличаться. Пожалуйста, убедитесь, что, когда ваш другой процесс умирает, вы видите, что как умирает. Наличие подпроцесса умирает, потому что пользователь убил его, как правило, требует другого ответа, чем выход, потому что он успешно завершил свою задачу.
Все самое лучшее,
Пол
Вы на 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 на меньшее значение и вызвать его в цикле (возможно, держать ручку hProc открытой, чтобы избежать повторного открытия другого процесса с одним и тем же PID).
Кроме того, у меня не было времени проверить этот фрагмент исходного кода, но я снял его с моего приложения, которое действительно работает.
может помочь, если бы мы знали, в какой среде вы работаете, стек технологии или язык ... – 2008-09-24 06:18:47