Domanda

Nell'app Windows C++, lancio diversi processi secondari a lunga esecuzione (attualmente utilizzo CreateProcess(...) per farlo.

Voglio che i processi figli vengano chiusi automaticamente se i miei processi principali si bloccano o è chiuso.

A causa del requisito che ciò debba funzionare in caso di arresto anomalo del "genitore", credo che ciò dovrebbe essere fatto utilizzando alcune API/funzionalità del sistema operativo.In modo che tutti i processi "figli" vengano ripuliti.

Come faccio a fare questo?

È stato utile?

Soluzione

L'API di Windows supporta oggetti chiamati "Oggetti lavoro".Il codice seguente creerà un "lavoro" configurato per arrestare tutti i processi al termine dell'applicazione principale (quando i suoi handle vengono ripuliti).Questo codice deve essere eseguito solo una volta.:

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);
    }
}

Quindi, quando viene creato ciascun processo figlio, eseguire il codice seguente per avviare ciascun processo figlio e aggiungerlo all'oggetto lavoro:

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:Vedere AssignProcessToJobObject restituisce sempre "accesso negato" su Vista se riscontri problemi di accesso negato con AssignProcessToObject() su Vista.

Altri suggerimenti

Una soluzione un po' hacker sarebbe che il processo genitore si collegasse a ciascun figlio come debugger (use DebugActiveProcess).Quando un debugger termina, vengono terminati anche tutti i suoi processi oggetto del debug.

Una soluzione migliore (supponendo che tu abbia scritto anche i processi figli) sarebbe quella di fare in modo che i processi figli monitorino il genitore e escano se scompare.

Oggetti lavoro di Windows sembra un buon punto di partenza.Il nome dell'oggetto lavoro dovrebbe essere ben noto o passato ai figli (o ereditare l'handle).I bambini dovrebbero essere avvisati quando il genitore muore, attraverso un "battito cardiaco" IPC fallito o semplicemente WFMO/WFSO sull'handle del processo del genitore.A quel punto qualsiasi processo figlio potrebbe TermianteJobObject far crollare l'intero gruppo.

È possibile mantenere in esecuzione un processo di watchdog separato.Il suo unico compito è osservare lo spazio del processo corrente per individuare situazioni come quelle che descrivi.Potrebbe anche riavviare l'applicazione originale dopo un arresto anomalo o fornire diverse opzioni all'utente, raccogliere informazioni di debug, ecc.Cerca solo di mantenerlo abbastanza semplice in modo da non aver bisogno di un secondo cane da guardia per controllare il primo.

Probabilmente dovresti tenere un elenco dei processi che avvii e terminarli uno per uno quando esci dal programma.Non sono sicuro delle specifiche per farlo in C++, ma non dovrebbe essere difficile.La parte difficile sarebbe probabilmente garantire che i processi figli vengano arrestati in caso di arresto anomalo dell'applicazione..Net ha la capacità di aggiungere una funzione che viene chiamata quando si verifica un'eccezione non gestita.Non sono sicuro che C++ offra le stesse funzionalità.

Potresti incapsulare ciascun processo in un oggetto C++ e mantenerne un elenco nell'ambito globale.I distruttori possono arrestare ogni processo.Funzionerà bene se il programma esce normalmente ma se si blocca, tutte le scommesse sono annullate.

Ecco un esempio approssimativo:

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

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

private:
    HANDLE _hProcess;
};

std::list<myprocess> allprocesses;

Quindi ogni volta che ne avvii uno, chiama allprocessess.push_back(hProcess);

Proprio in cima alla mia testa:

  • Hai considerato l'utilizzo di thread anziché di processi?
  • Prova a passare l'handle del thread/processo principale ai processi figli e chiedi loro di attendere su quell'handle.Funziona per i thread, poiché l'attesa su un handle di thread attende fino al completamento e alla chiusura del thread.Non sono sicuro che funzionerà per i processi, dovresti controllare MSDN per verificarlo.
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top