2009-08-18 4 views
9

간단한 웹 서버를 실행하는 하위 프로세스를 시작하는 응용 프로그램을 작성하고 있습니다. 나는 NSTask를 사용하고 파이프와 통신하고 있으며, 모든 것이 더 많거나 적은 것으로 보인다. 그러나 내 프로그램이 충돌하면 하위 프로세스가 생존하고 다음에 응용 프로그램을 시작할 때 이전 하위 프로세스와 새 하위 프로세스간에 충돌이 발생합니다. 소유하고있는 앱이 죽을 때 서브 프로세스가 죽는 것을 막을 수있는 방법이 있습니까?코코아에서 서브 프로세스가 죽었는지 확인하십시오.

+0

당신은 당신의 프로그램이 충돌하지 만드는 시도? : D – kubi

+0

여기 아틀라스에 대해 생각하고 있습니다 ^^ –

+0

Launchd에서 웹 서버를 실행할 수 있습니다. 최소한 앱이 충돌하고 다시 실행될 때 Launchd는 서버가 이미 실행 중이므로 종료하고 다시 시작할 수 있음을 알려줍니다. –

답변

1

애플리케이션 위임은

- (void)applicationWillTerminate:(NSNotification *)aNotification 

메시지를 구현하고 거기에 NSTask을 종료 할 수 있습니다. 그러나 충돌하는 동안이 대리자가 호출되는 것은 아닙니다.

두 가지 추가 단계는 수행 할 수 있습니다

  • 종료 새로운 부모 프로세스의 시작시 기존의 분리 된 서브 프로세스를 생성에 서브 프로세스의 디스크에 아래로 PID를 작성하고 정상 종료시 제거하여 (때로는 가장 안전한 행동이 아님).
  • NSPipe의 끝점이 하트 비트와 같은 특정 시간 동안 데이터를 보내지 않으면 하위 프로세스를 종료하십시오.
0

업데이트 : 이제 제대로 확인하기 위해 이동 했으므로 작동하지 않습니다. 이 오류로 인해 프로세스 그룹을 설정하려는 시도가 실패합니다.

EPERM "요청한 프로세스의 유효 사용자 ID가 호출자의 유효 사용자 ID와 다르며 프로세스가 호출 프로세스의 하위 항목이 아닙니다." 나는 내 응용 프로그램에서 Cocoadev 로버트 Pointon에 의해 제안을 시도했습니다

http://www.omnigroup.com/mailman/archive/macosx-dev/2009-March/062164.html


을 말할 수

는 지금까지이 문제를하지만 쉬운 솔루션에 최근 스레드 있습니다. 나는 아직 그것을 시험하고 싶지 않다.

http://www.cocoadev.com/index.pl?NSTaskTermination

아이디어는 작업 (아래 코드가 기본적으로 위의 스레드에서 해제되는 메모를) 시작하는 과정과 동일하게 작업의 프로세스 그룹을 설정하는 것입니다. 위의 작품

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 
} 
2

없음 ... 심지어 launchd 모두가 crappily 문서화 복잡도의이 일반적인 시나리오를 처리 할 수있는 방법이 없습니다. 나는 애플이 단지 백그라운드 프로세스를 실행하는 "모선 승인"방법을하지 않는 이유를 몰라,하지만 어떤 .. 내 솔루션은 ...

  1. 시작 쉘 스크립트를 NSTask를 통해 그것에게 당신이 필요로하는 모든 변수를 전달합니다. 또한 .. 차례로, 스크립트 내부 에서 서브 프로세스를 시작

  2. $ 1, $ 2 등을 통해 스크립트에서 이러한 읽기 등 int masterPID = [[NSProcessInfo processInfo] processIdentifier];을 통해 부모 프로세스의 PID 전달

  3. 스크립트 내의 하위 프로세스 을 모두 모니터링하십시오.죽 오프 좀비 고아 -

이것은 ".. 아이들에 눈을 유지"할 수 있습니다, 그리고 parentcide (또는 끔찍한 자동차 사고)의 슬픈 이벤트에 .. 이중 목적을 제공. 그런 다음 트리거를 당겨 (쉘 스크립트) 프로세스 테이블이 깨끗해질 것입니다. 마치 존재하지 않았던 것처럼. 차단 된 포트가 없으며 재발행시 충돌이없고 앱 스토어 거부가 발생하지 않습니다. Lemme이 도움이되는지 알아!

업데이트 : 나는 트릭을하는 Xcode 템플릿/daemon/project/whatever을 만들었습니다. 그것을 밖으로 검사하십시오 .. mralexgray/Infanticide.

1

다음 코드 샘플은 당신을 도울 것입니다.

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