Sto scrivendo un'applicazione che avvia un sottoprocesso che esegue un server Web semplice. Sto usando NSTask e comunico con esso con le pipe, e tutto sembra più o meno bello. Tuttavia, se il mio programma si arresta in modo anomalo, il sottoprocesso viene lasciato in vita e al prossimo avvio dell'app c'è un conflitto tra il vecchio sottoprocesso e il nuovo. C'è un modo per garantire che i sottoprocessi muoiano quando l'app proprietaria muore?Verificare che un sottoprocesso sia morto in Cocoa
risposta
Il delegato applicazione può implementare il messaggio
- (void)applicationWillTerminate:(NSNotification *)aNotification
, e terminare il NSTask lì. Tuttavia, non è garantito che durante un arresto, questo delegato venga chiamato.
due ulteriori passaggi si può prendere:
- Shutdown uno esistente, sottoprocesso orfani durante il lancio di un nuovo genitore-processo scrivendo su disco il PID del sottoprocesso sulla creazione e la rimozione durante l'arresto normale (a volte non è il comportamento più sicuro).
- Arresta il sottoprocesso se il punto finale dell'NSPipe non ha inviato dati per un intervallo di tempo specifico (qualcosa come un heartbeat).
AGGIORNAMENTO: Ora che vado a controllare correttamente, non funziona. Cercando di impostare il gruppo di processi non riesce con questo errore;
EPERM "L'ID utente effettivo del processo richiesto è diverso da quello del chiamante e il processo non è un discendente del processo di chiamata."
C'è un filo più recente su questo tema, ma non facile soluzione, per quanto posso dire
http://www.omnigroup.com/mailman/archive/macosx-dev/2009-March/062164.html
Ho provato un suggerimento di Robert Pointon sul Cocoadev nella mia app. Non ho ancora provato a provarlo.
http://www.cocoadev.com/index.pl?NSTaskTermination
L'idea è di impostare il gruppo processo del compito di essere la stessa di quella del processo che avvia l'attività (nota: il codice di seguito viene sostanzialmente sollevata dal filo sopra).
pid_t group = setsid();
if (group == -1) {
group = getpgrp();
}
[task launch];
if (setpgid([task processIdentifier], group) == -1) {
NSLog(@"unable to put task into same group as self");
[task terminate];
} else {
// handle running task
}
Nessuna delle opere di cui sopra ... Nemmeno launchd
in tutta la sua crappily-documentata complessità ha un modo per gestire questo scenario comune. Non so il motivo per cui Apple non si limita a fare un modo "madre-approvati" per eseguire i processi in background, ma qualunque cosa .. la mia soluzione è ...
lancio uno script shell tramite NSTask e passarlo tutte le variabili necessarie. passano anche nel processo padre PID via
int masterPID = [[NSProcessInfo processInfo] processIdentifier];
ecc Read questi nello script tramite $ 1, $ 2, eccA sua volta, avviare il sottoprocessi dal all'interno dello script ..
Monitorare sia il sottoprocesso AND processo genitore all'interno dello script.
Questo serve un duplice scopo .. si consente di "tenere d'occhio i bambini ..", e nella triste caso di parentcide (o incidente d'auto orribile) - kill-off gli orfani zombie. Quindi, premi il grilletto su te stesso (tu sei lo script di shell) e la tabella del processo sarà pulita .. come se non esistessi mai. Nessuna porta bloccata, nessun conflitto sul rilancio, nessun rifiuto dell'app store. Fammi sapere se questo aiuta!
Aggiornamento: Ho creato un modello/demone Xcode/progetto/qualsiasi cosa faccia il trucco. Dai un'occhiata .. mralexgray/Infanticide.
Il seguente codice di esempio dovrebbe aiutarti.
è preso in prestito da here,
#include <CoreFoundation/CoreFoundation.h>
#include <unistd.h>
#include <sys/event.h>
static void noteProcDeath(CFFileDescriptorRef fdref, CFOptionFlags callBackTypes, void *info) {
struct kevent kev;
int fd = CFFileDescriptorGetNativeDescriptor(fdref);
kevent(fd, NULL, 0, &kev, 1, NULL);
// take action on death of process here
printf("process with pid '%u' died\n", (unsigned int)kev.ident);
CFFileDescriptorInvalidate(fdref);
CFRelease(fdref); // the CFFileDescriptorRef is no longer of any use in this example
}
// one argument, an integer pid to watch, required
int main(int argc, char *argv[]) {
if (argc < 2) exit(1);
int fd = kqueue();
struct kevent kev;
EV_SET(&kev, atoi(argv[1]), EVFILT_PROC, EV_ADD|EV_ENABLE, NOTE_EXIT, 0, NULL);
kevent(fd, &kev, 1, NULL, 0, NULL);
CFFileDescriptorRef fdref = CFFileDescriptorCreate(kCFAllocatorDefault, fd, true, noteProcDeath, NULL);
CFFileDescriptorEnableCallBacks(fdref, kCFFileDescriptorReadCallBack);
CFRunLoopSourceRef source = CFFileDescriptorCreateRunLoopSource(kCFAllocatorDefault, fdref, 0);
CFRunLoopAddSource(CFRunLoopGetMain(), source, kCFRunLoopDefaultMode);
CFRelease(source);
// run the run loop for 20 seconds
CFRunLoopRunInMode(kCFRunLoopDefaultMode, 20.0, false);
return 0;
}
- 1. Come verificare che un file sia vuoto?
- 2. Come verificare che un JCheckBox sia selezionato?
- 3. Come verificare che un file sia caricato in un controller?
- 4. Verificare che un valore intero sia Nullo in C#
- 5. Come posso verificare che "qualcosa" sia un hash in Perl?
- 6. Verificare che un file STL sia ASCII o binario
- 7. Verificare che il termine sia un elenco di variabili distinte
- 8. Come verificare che sia stato trasmesso un tentativo
- 9. C# Come posso verificare che un file sia jpeg?
- 10. Verificare che un delegato sia stato chiamato con Moq
- 11. Query Postgres per verificare che una stringa sia un numero
- 12. Verificare che l'indirizzo di posta elettronica sia un utente paypal
- 13. Come verificare che la stringa non sia nulla in swift?
- 14. Verificare che un'espressione cron sia valida in Java
- 15. Come verificare che una stringa sia analizzabile in doppio?
- 16. come verificare che mod_deflate sia abilitato in apache?
- 17. Verificare che il record sia stato inserito correttamente in Symfony2
- 18. Come verificare che Apache2 sia bloccato in Ubuntu?
- 19. Come verificare sia null che non definito in js?
- 20. Come verificare che l'array previsto sia l'array effettivo in MSTest?
- 21. Come ottenere sia il codice di ritorno sia l'output dal sottoprocesso in Python?
- 22. Come posso verificare che un valore sia presente in un array (elenco) in Perl?
- 23. Come verificare che un oggetto modello sia persistente in DB o in un nuovo oggetto?
- 24. Come verificare che un campo stringa in un documento MongoDB non sia vuoto?
- 25. Come verificare che un attributo sia presente in un elemento utilizzando Selenium WebDriver?
- 26. Verificare che un'attività sia stata avviata con FLAG_ACTIVITY_CLEAR_TOP
- 27. Verificare che sia stata rilevata un'eccezione con Mockito e PowerMock
- 28. Verificare che la connessione al database psycopg2 sia attiva
- 29. Verificare che Java sia presente prima di installare
- 30. Posso verificare che una classe sia * non * predefinita costruibile?
Avete provato a fare il vostro programma va in crash? : D – kubi
Sto pensando ad Atlas qui ^^ –
Si potrebbe provare a eseguire il server Web in Launchd. Almeno in questo modo, quando la tua app si arresta e viene riavviata, Launchd ti dirà che il server è già in esecuzione, quindi puoi spegnerlo e riavviarlo se vuoi. –