Pregunta

En la aplicación C++ de Windows, inicio varios procesos secundarios de larga ejecución (actualmente uso CreateProcess(...) para hacer esto.

Quiero que los procesos secundarios se cierren automáticamente si mis procesos principales fallan o está cerrado.

Debido al requisito de que esto debe funcionar en caso de falla del "padre", creo que esto debería hacerse utilizando alguna API/función del sistema operativo.Para que se limpien todos los procesos "secundarios".

¿Cómo hago esto?

¿Fue útil?

Solución

La API de Windows admite objetos denominados "Objetos de trabajo".El siguiente código creará un "trabajo" que está configurado para cerrar todos los procesos cuando finaliza la aplicación principal (cuando se limpian sus identificadores).Este código sólo debe ejecutarse una vez:

HANDLE ghJob = CreateJobObject( NULL, NULL); // GLOBAL
if( ghJob == NULL)
{
    ::MessageBox( 0, "Could not create job object", "TEST", MB_OK);
}
else
{
    JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli = { 0 };

    // Configure all child processes associated with the job to terminate when the
    jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
    if( 0 == SetInformationJobObject( ghJob, JobObjectExtendedLimitInformation, &jeli, sizeof(jeli)))
    {
        ::MessageBox( 0, "Could not SetInformationJobObject", "TEST", MB_OK);
    }
}

Luego, cuando se cree cada proceso hijo, ejecute el siguiente código para iniciar cada proceso hijo y agregarlo al objeto de trabajo:

STARTUPINFO info={sizeof(info)};
PROCESS_INFORMATION processInfo;

// Launch child process - example is notepad.exe
if (::CreateProcess( NULL, "notepad.exe", NULL, NULL, TRUE, 0, NULL, NULL, &info, &processInfo))
{
    ::MessageBox( 0, "CreateProcess succeeded.", "TEST", MB_OK);
    if(ghJob)
    {
        if(0 == AssignProcessToJobObject( ghJob, processInfo.hProcess))
        {
            ::MessageBox( 0, "Could not AssignProcessToObject", "TEST", MB_OK);
        }
    }

    // Can we free handles now? Not sure about this.
    //CloseHandle(processInfo.hProcess); 
    CloseHandle(processInfo.hThread);
}

NOTA VISTA:Ver AssignProcessToJobObject siempre devuelve "acceso denegado" en Vista si encuentra problemas de acceso denegado con AssignProcessToObject() en Vista.

Otros consejos

Una solución un tanto pirateada sería que el proceso principal se adjunte a cada hijo como depurador (use Proceso activo de depuración).Cuando un depurador finaliza, todos sus procesos depurados también finalizan.

Una mejor solución (suponiendo que también haya escrito los procesos secundarios) sería hacer que los procesos secundarios supervisen al padre y salgan si desaparece.

Windows Job Objects parece un buen lugar para comenzar.El nombre del objeto de trabajo tendría que ser bien conocido o pasarse a los hijos (o heredar el identificador).Los niños necesitarían ser notificados cuando el padre muera, ya sea a través de un "latido" de IPC fallido o simplemente WFMO/WFSO en el identificador de proceso del padre.En ese punto, cualquier proceso hijo podría TermianteJobObject para derribar a todo el grupo.

Puede mantener en ejecución un proceso de vigilancia independiente.Su única tarea es observar el espacio del proceso actual para detectar situaciones como las que usted describe.Incluso podría reiniciar la aplicación original después de un fallo o proporcionar diferentes opciones al usuario, recopilar información de depuración, etc.Sólo trata de mantenerlo lo suficientemente simple como para que no necesites un segundo perro guardián para vigilar al primero.

Probablemente tendría que mantener una lista de los procesos que inicia y eliminarlos uno por uno cuando salga del programa.No estoy seguro de los detalles de hacer esto en C++ pero no debería ser difícil.La parte difícil probablemente sería garantizar que los procesos secundarios se cierren en caso de que la aplicación falle..Net tiene la capacidad de agregar una función que se llama cuando ocurre una excepción no controlada.No estoy seguro de si C++ ofrece las mismas capacidades.

Puede encapsular cada proceso en un objeto C++ y mantener una lista de ellos en el ámbito global.Los destructores pueden cerrar cada proceso.Eso funcionará bien si el programa sale normalmente pero falla, todas las apuestas están canceladas.

Aquí hay un ejemplo aproximado:

class myprocess
{
public:
    myprocess(HANDLE hProcess)
        : _hProcess(hProcess)
    { }

    ~myprocess()
    {
        TerminateProcess(_hProcess, 0);
    }

private:
    HANDLE _hProcess;
};

std::list<myprocess> allprocesses;

Luego, cada vez que inicie uno, llame a allprocessess.push_back(hProcess);

Justo al lado de la parte superior de mi cabeza:

  • ¿Ha considerado utilizar subprocesos en lugar de procesos?
  • Intente pasar el identificador del hilo/proceso principal a los procesos secundarios y haga que esperen en ese identificador.Esto funciona para subprocesos, ya que esperar en un identificador de subproceso espera hasta que ese subproceso se complete y salga.No estoy muy seguro de si funcionará para los procesos, debería consultar MSDN para verificar esto.
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top