माता-पिता के बाहर निकलने के बाद बच्चे की प्रक्रिया कैसे मर जाती है?


209

मान लीजिए कि मेरे पास एक प्रक्रिया है जो वास्तव में एक बच्चे की प्रक्रिया को जन्म देती है। अब जब अभिभावक प्रक्रिया जो भी कारण (सामान्य या असामान्य रूप से, मार, सी, मुखर विफलता या अन्य कुछ भी) के लिए बाहर निकलती है, मैं चाहता हूं कि बच्चे की प्रक्रिया मर जाए। कैसे सही ढंग से करने के लिए?


स्टैकओवरफ्लो पर कुछ ऐसे ही सवाल:


विंडोज के लिए स्टैकओवरफ्लो पर कुछ ऐसे ही सवाल :

जवाबों:


189

SIGHUPजब माता-पिता इस तरह syscall PR_SET_PDEATHSIGमें विकल्प निर्दिष्ट करके मर जाते हैं, तो बच्चा गिरी (या अन्य संकेत) देने के लिए कह सकता है prctl():

prctl(PR_SET_PDEATHSIG, SIGHUP);

man 2 prctlविवरण के लिए देखें।

संपादित करें: यह केवल Linux है


5
यह एक खराब समाधान है क्योंकि माता-पिता पहले ही मर चुके होंगे। दौड़ की स्थिति। सही समाधान: stackoverflow.com/a/17589555/412080
मैक्सिम एगोरुस्किन

16
एक जवाब गरीब को कॉल करना बहुत अच्छा नहीं है - भले ही वह दौड़ की स्थिति को संबोधित नहीं करता हो। रेस-कंडीशन फ्री में कैसे इस्तेमाल करें , इस पर मेरा जवाब देखें prctl()। Btw, मैक्सिम द्वारा जुड़ा जवाब गलत है।
मैक्सक्लेपज़िग

4
यह सिर्फ एक गलत आंसर है। यह उस समय बच्चे की प्रक्रिया को संकेत भेजेगा जब धागा जिसे कांटा मर जाता है, तब नहीं जब मूल प्रक्रिया मर जाती है।
लोथर

2
@ लोथर को किसी तरह का प्रमाण देखना अच्छा होगा। man prctlकहते हैं: कॉल करने की प्रक्रिया के पैरेंट प्रोसेस डेथ सिग्नल को arg2 पर सेट करें (या तो रेंज 1..maxsig में सिग्नल वैल्यू, या 0 क्लियर करने के लिए)। यह संकेत है कि कॉलिंग प्रक्रिया तब मिलेगी जब उसके माता-पिता की मृत्यु हो जाएगी। यह मान एक कांटा (2) और (लिनक्स 2.4.36 / 2.6.23 के बाद से) के बच्चे के लिए मंजूरी दे दी है जब एक सेट-यूजर-आईडी या सेट-ग्रुप-आईडी बाइनरी निष्पादित करते हैं।
qrdl

1
@maxschlepzig नए लिंक के लिए धन्यवाद। पिछले लिंक की तरह लगता है अमान्य है। वैसे, वर्षों के बाद, माता-पिता की ओर से विकल्प स्थापित करने के लिए अभी भी कोई एपीआई नहीं है। अफ़सोस की बात है।
रॉक्स

68

मैं उसी समस्या को हल करने की कोशिश कर रहा हूं, और चूंकि मेरा कार्यक्रम ओएस एक्स पर चलना चाहिए, लिनक्स-केवल समाधान मेरे लिए काम नहीं करता था।

मैं इस पृष्ठ पर अन्य लोगों के समान निष्कर्ष पर आया था - माता-पिता के मरने पर बच्चे को सूचित करने का POSIX- संगत तरीका नहीं है। इसलिए मैंने अगली सबसे अच्छी बात यह बताई कि - बच्चे को पोल करवाना।

जब एक माता-पिता की प्रक्रिया किसी भी कारण से मर जाती है, तो बच्चे की माता-पिता की प्रक्रिया 1 हो जाती है। यदि बच्चा समय-समय पर मतदान करता है, तो यह जांच कर सकता है कि क्या उसका माता-पिता 1. यदि यह है, तो बच्चे को बाहर निकलना चाहिए।

यह बहुत अच्छा नहीं है, लेकिन यह काम करता है, और इस पृष्ठ पर कहीं और सुझाए गए टीसीपी सॉकेट / लॉकफाइल मतदान समाधानों की तुलना में आसान है।


6
उत्कृष्ट समाधान। जब तक यह 1 वापस नहीं आता तब तक गेटपिड () को लगातार लागू करना और फिर बाहर निकलना। यह अच्छा है और मैं अब इसका भी उपयोग करता हूं। एक गैर-पराग समाधान हालांकि अच्छा होगा। शुक्रिया शुक्रिया।
नीनी

10
बस जानकारी के लिए, यदि आप ज़ोन में हैं, तो सोलारिस पर, gettpid()1 नहीं बनता है बल्कि pidज़ोन शेड्यूलर (प्रक्रिया zsched) का हो जाता है ।
पैट्रिक श्ल्टर

4
अगर किसी को आश्चर्य हो रहा है, तो एंड्रॉइड सिस्टम में पेरेंट के मरने पर 1 की बजाय 0 (प्रोसेस सिस्टम पीआईडी) लगता है।
रुई मार्केज

2
कांटा () - आईएनजी, बस गेटपिड () और यदि गेटपिड () बच्चे से अलग है, तो बाहर निकलने से पहले इसे और अधिक मजबूत और स्वतंत्र तरीके से करना होगा।
सेबस्टियन

2
यदि आप बच्चे की प्रक्रिया को नियंत्रित नहीं करते हैं तो यह काम नहीं करता है। उदाहरण के लिए, मैं एक कमांड पर काम कर रहा हूं जो रैप (1) खोजता है, और मैं यह सुनिश्चित करना चाहता हूं कि यदि किसी कारण से रैपर की मृत्यु हो जाए तो वह खोज मारा जाता है।
ल्यूक्रिएल

34

मैंने इसे "बच्चे" में "मूल" कोड और "पैरेंट" में "स्पॉम्ड" कोड चलाकर प्राप्त किया है (यानी: आप परीक्षण के सामान्य अर्थ को उल्टा करते हैं fork())। फिर "स्पॉन्ड" कोड में SIGCHLD को फंसाएं ...

आपके मामले में संभव नहीं है, लेकिन जब यह काम करेगा तब प्यारा होगा।


बहुत अच्छा समाधान, धन्यवाद! वर्तमान में स्वीकृत एक और अधिक सामान्य है, लेकिन आपका अधिक पोर्टेबल है।
पावेल हज्दान

1
माता-पिता में काम करने के साथ बड़ी समस्या यह है कि आप मूल प्रक्रिया को बदल रहे हैं। एक सर्वर के मामले में जिसे "हमेशा के लिए" चलाना है, वह विकल्प नहीं है।
एलेक्सिस विल्के

29

यदि आप बच्चे की प्रक्रिया को संशोधित करने में असमर्थ हैं, तो आप कुछ इस तरह की कोशिश कर सकते हैं:

int pipes[2];
pipe(pipes)
if (fork() == 0) {
    close(pipes[1]); /* Close the writer end in the child*/
    dup2(0, pipes[0]); /* Use reader end as stdin */
    exec("sh -c 'set -o monitor; child_process & read dummy; kill %1'")
}

close(pipes[0]); /* Close the reader end in the parent */

यह बच्चे को शेल प्रक्रिया के भीतर से चलाता है जिसमें नौकरी नियंत्रण सक्षम है। बच्चे की प्रक्रिया पृष्ठभूमि में पैदा होती है। शेल एक नई रेखा (या एक ईओएफ) की प्रतीक्षा करता है फिर बच्चे को मारता है।

जब माता-पिता की मृत्यु हो जाती है - चाहे कोई भी कारण हो - यह पाइप के अपने अंत को बंद कर देगा। बच्चे के खोल को पढ़ने से एक ईओएफ मिलेगा और पृष्ठभूमि वाले बच्चे की प्रक्रिया को मारने के लिए आगे बढ़ना होगा।


2
अच्छा है, लेकिन पांच सिस्टम कॉल, और कोड की दस लाइनों में एक shawned कोड के प्रदर्शन के इस टुकड़े के बारे में मुझे थोड़ा संदेह है।
ओलीडे

+1। आप किसी विशिष्ट फ़ाइल डिस्क्रिप्टर से पढ़ने के dup2लिए read -uध्वज का उपयोग करके स्टड को लेने और उससे बचने के लिए कर सकते हैं । मैंने setpgid(0, 0)टर्मिनल में ^ C दबाने पर इसे बाहर निकलने से रोकने के लिए बच्चे में एक जोड़ा ।
ग्रेग हेविल

dup2()कॉल का तर्क क्रम गलत है। यदि आप pipes[0]स्टडिन के रूप में उपयोग करना चाहते हैं तो आपको dup2(pipes[0], 0)इसके बजाय लिखना होगा dup2(0, pipes[0])। यह वह dup2(oldfd, newfd)जगह है जहाँ कॉल एक पहले से खुले newfd को बंद कर देता है।
मैक्सक्लेपज़िग

@ ओलीडे, मैं सहमत हूं, खासकर जब से शॉक्ड श असली बच्चे की प्रक्रिया को अंजाम देने के लिए सिर्फ एक और कांटा करता है ...
maxschlepzig

16

लिनक्स के तहत, आप बच्चे में माता-पिता की मौत का संकेत स्थापित कर सकते हैं, जैसे:

#include <sys/prctl.h> // prctl(), PR_SET_PDEATHSIG
#include <signal.h> // signals
#include <unistd.h> // fork()
#include <stdio.h>  // perror()

// ...

pid_t ppid_before_fork = getpid();
pid_t pid = fork();
if (pid == -1) { perror(0); exit(1); }
if (pid) {
    ; // continue parent execution
} else {
    int r = prctl(PR_SET_PDEATHSIG, SIGTERM);
    if (r == -1) { perror(0); exit(1); }
    // test in case the original parent exited just
    // before the prctl() call
    if (getppid() != ppid_before_fork)
        exit(1);
    // continue child execution ...

ध्यान दें कि कांटे से पहले माता-पिता की प्रक्रिया आईडी को संग्रहीत करना और बच्चे के prctl()बीच दौड़ की स्थिति को समाप्त करने prctl()और बच्चे को बुलाया जाने वाली प्रक्रिया से बाहर निकलने के बाद इसका परीक्षण करना ।

यह भी ध्यान दें कि बच्चे के माता-पिता की मृत्यु का संकेत अपने स्वयं के नए बनाए गए बच्चों में है। यह एक से प्रभावित नहीं है execve()

उस परीक्षा को सरल बनाया जा सकता है यदि हम निश्चित हों कि सिस्टम प्रक्रिया जो सभी अनाथ बच्चों को अपनाने के लिए है, उनके पास PID 1 है:

pid_t pid = fork();
if (pid == -1) { perror(0); exit(1); }
if (pid) {
    ; // continue parent execution
} else {
    int r = prctl(PR_SET_PDEATHSIG, SIGTERM);
    if (r == -1) { perror(0); exit(1); }
    // test in case the original parent exited just
    // before the prctl() call
    if (getppid() == 1)
        exit(1);
    // continue child execution ...

initहालाँकि, उस सिस्टम प्रक्रिया पर भरोसा करना और PID 1 होना पोर्टेबल नहीं है, हालाँकि। POSIX.1-2008 निर्दिष्ट करता है :

मौजूदा बच्चे की सभी प्रक्रियाओं की मूल प्रक्रिया आईडी और कॉलिंग प्रक्रिया की ज़ोंबी प्रक्रिया एक कार्यान्वयन-परिभाषित प्रक्रिया प्रक्रिया की प्रक्रिया आईडी पर सेट की जाएगी। यही है, इन प्रक्रियाओं को एक विशेष प्रणाली प्रक्रिया द्वारा विरासत में मिला होगा।

परंपरागत रूप से, सभी अनाथों को अपनाने वाली प्रणाली प्रक्रिया PID 1 है, अर्थात init - जो सभी प्रक्रियाओं का पूर्वज है।

लिनक्स या फ्रीबीएसडी जैसी आधुनिक प्रणालियों में एक और प्रक्रिया की भूमिका हो सकती है। उदाहरण के लिए, लिनक्स पर, एक प्रक्रिया prctl(PR_SET_CHILD_SUBREAPER, 1)खुद को सिस्टम प्रक्रिया के रूप में स्थापित करने के लिए कॉल कर सकती है जो इसके किसी भी वंशज के सभी अनाथों को विरासत में मिला है (cf. फेडोरा 25 पर एक उदाहरण )।


मुझे समझ में नहीं आता है कि "अगर हम निश्चित हैं कि दादा दादी हमेशा init प्रक्रिया है" तो इस परीक्षा को सरल बनाया जा सकता है। जब माता-पिता की प्रक्रिया मर जाती है, तो एक प्रक्रिया init प्रक्रिया का बच्चा बन जाती है (पृष्ठ 1), दादा-दादी का बच्चा नहीं, सही? इसलिए परीक्षा हमेशा सही लगती है।
जोहान्स शाउब -


दिलचस्प है, धन्यवाद। हालाँकि, मैं यह देखने में असफल रहा कि इसका दादा-दादी के साथ क्या संबंध है।
जोहान्स शहाब -

1
@ जोहान्सचैब-लिटब, आप हमेशा यह नहीं मान सकते हैं कि एक प्रक्रिया के दानेदार होने की प्रक्रिया होगी init(8).... केवल एक चीज जिसे आप मान सकते हैं कि जब एक माता-पिता की प्रक्रिया मर जाती है, तो यह है कि इसकी मूल आईडी बदल जाएगी। यह वास्तव में एक प्रक्रिया के जीवन में एक बार होता है .... और जब प्रक्रिया के माता-पिता की मृत्यु हो जाती है। इसका केवल एक मुख्य अपवाद है, और init(8)बच्चों के लिए है, लेकिन आप इससे सुरक्षित हैं, जैसा कि उस मामले में init(8)कभी exit(2)(कर्नेल पैनिक) नहीं है
लुइस कोलोराडो

1
दुर्भाग्य से, यदि बच्चा थ्रेड से कांटा करता है, और फिर थ्रेड बाहर निकलता है, तो चाइल्ड प्रोसेस wil को SIGTERM मिलता है।
रॉक्स

14

पूर्णता के लिए। MacOS पर आप kqueue का उपयोग कर सकते हैं:

void noteProcDeath(
    CFFileDescriptorRef fdref, 
    CFOptionFlags callBackTypes, 
    void* info) 
{
    // LOG_DEBUG(@"noteProcDeath... ");

    struct kevent kev;
    int fd = CFFileDescriptorGetNativeDescriptor(fdref);
    kevent(fd, NULL, 0, &kev, 1, NULL);
    // take action on death of process here
    unsigned int dead_pid = (unsigned int)kev.ident;

    CFFileDescriptorInvalidate(fdref);
    CFRelease(fdref); // the CFFileDescriptorRef is no longer of any use in this example

    int our_pid = getpid();
    // when our parent dies we die as well.. 
    LOG_INFO(@"exit! parent process (pid %u) died. no need for us (pid %i) to stick around", dead_pid, our_pid);
    exit(EXIT_SUCCESS);
}


void suicide_if_we_become_a_zombie(int parent_pid) {
    // int parent_pid = getppid();
    // int our_pid = getpid();
    // LOG_ERROR(@"suicide_if_we_become_a_zombie(). parent process (pid %u) that we monitor. our pid %i", parent_pid, our_pid);

    int fd = kqueue();
    struct kevent kev;
    EV_SET(&kev, parent_pid, 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);
}

DISPATCH_SOURCE_PROC और PROCATEXIT के साथ प्रेषण स्रोतों का उपयोग करके आप इसे थोड़ा अच्छे एपीआई के साथ कर सकते हैं।
रुसबिशप

जो भी कारण के लिए, यह मेरे मैक को आतंकित कर रहा है। इस कोड के साथ एक प्रक्रिया चलाने के लिए 50% मौका या इसके जमने का कारण होता है, जिससे प्रशंसकों को ऐसी दर पर स्पिन करने को मिलता है जो मैंने कभी नहीं सुना है कि उन्हें पहले (सुपर फास्ट) जाना है, और फिर मैक बस बंद हो जाता है। इस कोड के साथ बहुत सावधान रहना चाहिए
Qix - मोनासा

यह मेरे macOS पर लगता है, माता-पिता के बाहर निकलने के बाद बच्चे की प्रक्रिया अपने आप बाहर निकल जाती है। मुझे पता नहीं क्यों।
यी लिन लियू

@YiLinLiu iirc का उपयोग मैंने किया NSTaskया पॉज़िक्स स्पॉन। startTaskयहाँ मेरे कोड में फ़ंक्शन देखें : github.com/neoneye/newton-commander-browse/blob/master/Classes/…
neoneye

11

क्या बच्चे की प्रक्रिया में मूल प्रक्रिया से / से पाइप है? यदि ऐसा है, तो आपको एक SIGPIPE प्राप्त होगा यदि लेखन, या पढ़ते समय EOF प्राप्त करें - इन स्थितियों का पता लगाया जा सकता है।


1
मैंने पाया कि यह मज़बूती से नहीं हुआ, कम से कम OS X पर
Schof

मैं इस जवाब को जोड़ने के लिए यहां आया था। यह निश्चित रूप से समाधान है जो मैं इस मामले के लिए उपयोग करूंगा।
डोलडॉना २२

सावधानियों का बिंदु: सिस्टम इसे प्रबंधित करने वाली सेवाओं में डिफ़ॉल्ट रूप से SIGPIPE को निष्क्रिय कर देता है, लेकिन फिर भी आप पाइप बंद होने की जांच कर सकते हैं। देखें freedesktop.org/software/systemd/man/systemd.exec.html तहत IgnoreSIGPIPE
jdizzle

11

यहाँ एक अन्य उत्तर से प्रेरित होकर, मैं निम्नलिखित सभी POSIX समाधान के साथ आया। सामान्य विचार माता-पिता और बच्चे के बीच एक मध्यवर्ती प्रक्रिया बनाना है, जिसका एक उद्देश्य है: नोटिस जब माता-पिता की मृत्यु हो जाती है, और स्पष्ट रूप से बच्चे को मारते हैं।

इस प्रकार का समाधान तब उपयोगी होता है जब बच्चे में कोड को संशोधित नहीं किया जा सकता है।

int p[2];
pipe(p);
pid_t child = fork();
if (child == 0) {
    close(p[1]); // close write end of pipe
    setpgid(0, 0); // prevent ^C in parent from stopping this process
    child = fork();
    if (child == 0) {
        close(p[0]); // close read end of pipe (don't need it here)
        exec(...child process here...);
        exit(1);
    }
    read(p[0], 1); // returns when parent exits for any reason
    kill(child, 9);
    exit(1);
}

इस विधि के साथ दो छोटे गुच्छे हैं:

  • यदि आप जानबूझकर मध्यवर्ती प्रक्रिया को मारते हैं, तो माता-पिता के मरने पर बच्चा नहीं मारा जाएगा।
  • यदि बच्चा माता-पिता से पहले बाहर निकलता है, तो मध्यवर्ती प्रक्रिया मूल बच्चे को मारने की कोशिश करेगी, जो अब एक अलग प्रक्रिया को संदर्भित कर सकती है। (यह मध्यवर्ती प्रक्रिया में अधिक कोड के साथ तय किया जा सकता है।)

एक तरफ के रूप में, मैं जिस वास्तविक कोड का उपयोग कर रहा हूं वह पायथन में है। यहाँ यह पूर्णता के लिए है:

def run(*args):
    (r, w) = os.pipe()
    child = os.fork()
    if child == 0:
        os.close(w)
        os.setpgid(0, 0)
        child = os.fork()
        if child == 0:
            os.close(r)
            os.execl(args[0], *args)
            os._exit(1)
        os.read(r, 1)
        os.kill(child, 9)
        os._exit(1)
    os.close(r)

ध्यान दें कि कुछ समय पहले, IRIX के तहत, मैंने एक पैरेंट / चाइल्ड स्कीम का इस्तेमाल किया था, जहाँ मैं दोनों के बीच एक पाइप था और पाइप से रीडिंग ने एक SIGHUP उत्पन्न किया यदि दोनों में से किसी एक की मृत्यु हो गई। यह वह तरीका था जो मैंने अपने कांटे () के एड बच्चों को मारने के लिए इस्तेमाल किया, एक मध्यवर्ती प्रक्रिया की आवश्यकता के बिना।
एलेक्सिस विल्के

मुझे लगता है कि आपका दूसरा चेतावनी गलत है। एक बच्चे का पिड उसके माता-पिता से संबंधित एक संसाधन है और इसे तब तक मुक्त / पुन: उपयोग नहीं किया जा सकता है जब तक कि माता-पिता (मध्यवर्ती प्रक्रिया) उस पर इंतजार नहीं करता (या समाप्त करता है और इनिट को प्रतीक्षा करने देता है)।
आर .. गिटहब स्टॉप हेल्पिंग ICE

7

मुझे विश्वास नहीं है कि केवल मानक POSIX कॉल का उपयोग करके यह गारंटी देना संभव है। वास्तविक जीवन की तरह, एक बार जब एक बच्चे को जन्म दिया जाता है, तो उसका अपना जीवन होता है।

यह है माता पिता की प्रक्रिया सबसे संभावित समाप्ति की घटनाओं को पकड़ने के लिए, और उस बिंदु पर बच्चे प्रक्रिया को मारने के लिए प्रयास करने के लिए संभव है, लेकिन वहाँ हमेशा कुछ है कि पकड़ा नहीं किया जा सकता है।

उदाहरण के लिए, कोई भी प्रक्रिया नहीं पकड़ सकती है SIGKILL। जब कर्नेल इस सिग्नल को संभालता है तो यह उस प्रक्रिया को बिना किसी अधिसूचना के निर्दिष्ट प्रक्रिया को मार देगा।

सादृश्य का विस्तार करने के लिए - यह करने का एकमात्र अन्य मानक तरीका है कि बच्चा आत्महत्या कर ले, जब यह पाता है कि उसके पास अब माता-पिता नहीं हैं।

इसके साथ करने का केवल एक लिनक्स है prctl(2)- अन्य जवाब देखें।


6

जैसा कि अन्य लोगों ने इंगित किया है, जब माता-पिता बाहर निकलते हैं तो गैर-पोर्टेबल होने पर माता-पिता के पी 1 पर भरोसा करना। किसी विशिष्ट मूल प्रक्रिया ID की प्रतीक्षा करने के बजाय, बस ID बदलने की प्रतीक्षा करें:

pit_t pid = getpid();
switch (fork())
{
    case -1:
    {
        abort(); /* or whatever... */
    }
    default:
    {
        /* parent */
        exit(0);
    }
    case 0:
    {
        /* child */
        /* ... */
    }
}

/* Wait for parent to exit */
while (getppid() != pid)
    ;

यदि आप पूर्ण गति से मतदान नहीं करना चाहते हैं, तो एक सूक्ष्म नींद जोड़ें।

यह विकल्प मुझे एक पाइप का उपयोग करने या संकेतों पर भरोसा करने की तुलना में सरल लगता है।


दुर्भाग्य से, यह समाधान मजबूत नहीं है। यदि प्रारंभिक मूल्य प्राप्त करने से पहले मूल प्रक्रिया मर जाती है तो क्या होगा? बच्चा कभी बाहर नहीं निकलेगा।
डगटवुड

@ दगाटवुड, आपका क्या मतलब है? पहला getpid()कॉल करने से पहले माता-पिता में किया जाता है fork()। यदि माता-पिता इससे पहले मर जाते हैं कि बच्चा मौजूद नहीं है। क्या हो सकता है कि बच्चा कुछ समय के लिए माता-पिता के साथ रहे।
एलेक्सिस विल्के

इस थोड़े से वंचित उदाहरण में, यह काम करता है, लेकिन वास्तविक दुनिया कोड में, कांटा लगभग हमेशा निष्पादन के बाद होता है, और नई प्रक्रिया को अपने पीपीआईडी ​​के लिए पूछकर शुरू करना चाहिए। उन दो जांचों के बीच के समय में, अगर माता-पिता चले जाते हैं, तो बच्चे को पता नहीं चलेगा। इसके अलावा, आपको माता-पिता और बाल कोड दोनों पर नियंत्रण होने की संभावना नहीं है (या आप एक तर्क के रूप में पीपीआईडी ​​को पारित कर सकते हैं)। तो एक सामान्य समाधान के रूप में, यह दृष्टिकोण बहुत अच्छी तरह से काम नहीं करता है। और वास्तविक रूप से, अगर एक UNIX जैसा OS बिना init 1 के बाहर आया, तो इतना सामान टूट जाएगा कि मैं किसी भी तरह से करने की कल्पना नहीं कर सकता।
dgatwood

पास अभिभावक बच्चे के लिए निष्पादन करते समय कमांड लाइन तर्क है।
निशि

2
पूरी गति से मतदान करना पागलपन है।
मैक्सक्लेपज़िग

4

SIGINT को पकड़ने के लिए एक ट्रैप हैंडलर स्थापित करें , जो आपके बच्चे की प्रक्रिया को मारता है यदि यह अभी भी जीवित है, हालांकि अन्य पोस्टर सही हैं कि यह SIGKILL नहीं पकड़ेगा।

एक्सक्लूसिव एक्सेस के साथ एक .lockfile खोलें और इसे खोलने की कोशिश में बच्चे पर पोल करें - यदि ओपन सफल होता है, तो बच्चे की प्रक्रिया से बाहर निकलने की प्रक्रिया


या, बच्चा लॉकिंग मोड को एक अलग थ्रेड में, अवरुद्ध मोड में खोल सकता है, इस मामले में यह एक बहुत अच्छा और साफ समाधान हो सकता है। संभवतः इसकी कुछ पोर्टेबिलिटी सीमाएँ हैं।
जीन

4

इस समाधान ने मेरे लिए काम किया:

  • बच्चे को स्टड पाइप पास करें - आपको स्ट्रीम में कोई डेटा लिखने की आवश्यकता नहीं है।
  • बच्चा स्टड से अनिश्चित काल तक ईओडी तक पढ़ता है। एक ईओएफ संकेत करता है कि माता-पिता चले गए हैं।
  • यह पता लगाने के लिए मूर्खतापूर्ण और पोर्टेबल तरीका है कि माता-पिता कब गए हैं। यदि पैरेंट क्रैश हो जाता है, तो भी OS पाइप बंद कर देगा।

यह एक कार्यकर्ता-प्रकार की प्रक्रिया के लिए था जिसका अस्तित्व केवल तभी समझ में आता था जब माता-पिता जीवित थे।


@SebastianJylanki मुझे याद नहीं है कि मैंने कोशिश की थी, लेकिन यह शायद इसलिए काम करता है क्योंकि प्राइमेटिव (POSIX स्ट्रीम) OS के पार काफी मानक हैं।
joonas.fi

3

मुझे लगता है कि बच्चे और माता-पिता के बीच एक पाइप बनाने के लिए एक त्वरित और गंदा तरीका है। जब माता-पिता बाहर निकलते हैं, तो बच्चे एक SIGPIPE प्राप्त करेंगे।


SIGPIPE को पाइप के पास नहीं भेजा जाता है, यह केवल तभी भेजा जाता है जब बच्चा इसे लिखने की कोशिश करता है।
अल्करो

3

कुछ पोस्टरों में पहले से ही पाइप और उल्लेख किया गया है kqueue। वास्तव में आप कॉल द्वारा जुड़े यूनिक्स डोमेन सॉकेट की एक जोड़ी भी बना सकते हैं socketpair()। सॉकेट प्रकार होना चाहिए SOCK_STREAM

मान लें कि आपके पास दो सॉकेट फ़ाइल डिस्क्रिप्टर fd1, fd2 है। अब fork()बच्चे की प्रक्रिया बनाने के लिए, जो कि एफडीएस को विरासत में मिलेगा। माता-पिता में आप fd2 को बंद करते हैं और बच्चे में आप fd1 को बंद कर देते हैं। अब प्रत्येक प्रक्रिया ईवेंट के poll()लिए अपने स्वयं के अंत में शेष खुली एफडी कर सकती है POLLIN। जब तक प्रत्येक पक्ष close()सामान्य जीवनकाल के दौरान स्पष्ट रूप से अपनी एफडी नहीं करता है , तब तक आप पूरी तरह से सुनिश्चित हो सकते हैं कि एक POLLHUPध्वज को दूसरे की समाप्ति (कोई बात नहीं या साफ नहीं) का संकेत देना चाहिए। इस घटना के अधिसूचित होने पर, बच्चा यह तय कर सकता है कि क्या करना है (जैसे मरने के लिए)।

#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <poll.h>
#include <stdio.h>

int main(int argc, char ** argv)
{
    int sv[2];        /* sv[0] for parent, sv[1] for child */
    socketpair(AF_UNIX, SOCK_STREAM, 0, sv);

    pid_t pid = fork();

    if ( pid > 0 ) {  /* parent */
        close(sv[1]);
        fprintf(stderr, "parent: pid = %d\n", getpid());
        sleep(100);
        exit(0);

    } else {          /* child */
        close(sv[0]);
        fprintf(stderr, "child: pid = %d\n", getpid());

        struct pollfd mon;
        mon.fd = sv[1];
        mon.events = POLLIN;

        poll(&mon, 1, -1);
        if ( mon.revents & POLLHUP )
            fprintf(stderr, "child: parent hung up\n");
        exit(0);
    }
}

आप उपरोक्त प्रूफ-ऑफ-कांसेप्ट कोड को संकलित करने की कोशिश कर सकते हैं, और इसे किसी टर्मिनल में चला सकते हैं ./a.out &। आपके पास विभिन्न संकेतों द्वारा माता-पिता पीआईडी ​​को मारने के लिए प्रयोग करने में लगभग 100 सेकंड हैं, या यह बस बाहर निकल जाएगा। किसी भी मामले में, आपको "बच्चे: माता-पिता को लटका हुआ" संदेश देखना चाहिए।

SIGPIPEहैंडलर का उपयोग करने की विधि की तुलना में , इस विधि को write()कॉल करने की आवश्यकता नहीं है ।

यह विधि सममित भी है , अर्थात प्रक्रियाएं एक दूसरे के अस्तित्व की निगरानी के लिए एक ही चैनल का उपयोग कर सकती हैं।

यह समाधान केवल POSIX फ़ंक्शन को कॉल करता है। मैंने लिनक्स और फ्रीबीएसडी में इसकी कोशिश की। मुझे लगता है कि इसे अन्य यूनिक्स पर काम करना चाहिए लेकिन मैंने वास्तव में परीक्षण नहीं किया है।

यह सभी देखें:

  • unix(7)लिनक्स आदमी पृष्ठों की, unix(4)FreeBSD के लिए, poll(2), socketpair(2), socket(7)लिनक्स पर।

बहुत अच्छा है, मैं वास्तव में सोच रहा था कि यह कोई विश्वसनीयता मुद्दे हैं। क्या आपने उत्पादन में इसका परीक्षण किया है? अलग-अलग ऐप के साथ?
अकटौ

@ अक्ताउ, मैं एक लिनक्स प्रोग्राम में इस ट्रिक के बराबर पायथन का उपयोग कर रहा हूं। मुझे इसकी आवश्यकता थी क्योंकि बच्चे के कामकाजी तर्क "माता-पिता के बाहर निकलने के बाद सबसे अच्छा प्रयास करने के लिए सफाई करना और फिर बाहर निकलना है"। हालांकि, मैं वास्तव में अन्य प्लेटफार्मों के बारे में निश्चित नहीं हूं। सी स्निपेट लिनक्स और फ्रीबीएसडी पर काम करता है, लेकिन यह सब मुझे पता है ... इसके अलावा, ऐसे मामले हैं जब आपको सावधान रहना चाहिए, जैसे कि माता-पिता फिर से फोर्किंग करते हैं, या माता-पिता वास्तव में बाहर निकलने से पहले एफडी छोड़ देते हैं (इस प्रकार एक समय खिड़की के लिए दौड़ की स्थिति)।
कांग्रेस मा

@ अकतऊ - यह पूरी तरह से विश्वसनीय होगा।
18

1

के तहत POSIX , exit(), _exit()और _Exit()कार्यों के लिए परिभाषित कर रहे हैं:

  • यदि प्रक्रिया एक नियंत्रण प्रक्रिया है, तो कॉलिंग प्रक्रिया से संबंधित नियंत्रण टर्मिनल के अग्रभूमि प्रक्रिया समूह में प्रत्येक प्रक्रिया के लिए SITEUP संकेत भेजा जाएगा।

इसलिए, यदि आप मूल प्रक्रिया के लिए उसके प्रक्रिया समूह के लिए एक नियंत्रित प्रक्रिया होने की व्यवस्था करते हैं, तो माता-पिता के बैठने पर बच्चे को एक साइट सिग्नल मिलना चाहिए। मुझे बिलकुल यकीन नहीं है कि जब अभिभावक दुर्घटनाग्रस्त होता है, लेकिन मुझे लगता है कि यह होता है। निश्चित रूप से, गैर-दुर्घटना मामलों के लिए, यह ठीक काम करना चाहिए।

नोट आप ठीक प्रिंट की काफी एक बहुत कुछ पढ़ने के लिए हो सकता है - के लिए बेस परिभाषाएं (परिभाषाएं) अनुभाग सहित, साथ ही सिस्टम सेवाएं जानकारी exit()और setsid()और setpgrp()- पूरी तस्वीर प्राप्त करने के लिए। (तो क्या मैं!)


3
हम्म। प्रलेखन इस पर अस्पष्ट और विरोधाभासी है, लेकिन ऐसा प्रतीत होता है कि मूल प्रक्रिया सत्र के लिए मुख्य प्रक्रिया होनी चाहिए, न कि केवल प्रक्रिया समूह। सत्र के लिए लीड प्रक्रिया हमेशा लॉगिन थी, और नए सत्र के लिए लीड प्रक्रिया के रूप में कार्यभार संभालने की मेरी प्रक्रिया इस समय मेरी क्षमताओं से परे थी।
Schof

2
यदि बाहर निकलने की प्रक्रिया एक लॉगिन शेल है, तो SIGHUP प्रभावी रूप से केवल चाइल्ड प्रोसेस को भेजा जाता है। opengroup.org/onlinepubs/009695399/functions/exit.html "किसी प्रक्रिया की समाप्ति सीधे उसके बच्चों को समाप्त नहीं करती है। जैसा कि नीचे वर्णित SITEUP संकेत भेजना अप्रत्यक्ष रूप से बच्चों को / कुछ परिस्थितियों में समाप्त करता है।"
रोब के

1
@ रब: सही - वह उद्धरण जो मैंने दिया है, यह भी कहता है: कि केवल कुछ परिस्थितियों में बच्चे की प्रक्रिया को एक साइट मिल जाती है। और यह कड़ाई से अति-सरलीकरण है कि यह केवल एक लॉगिन शेल है जो SIGHUP भेजता है, हालांकि यह सबसे आम मामला है। यदि कई बच्चों के साथ एक प्रक्रिया अपने आप को और अपने बच्चों के लिए नियंत्रण प्रक्रिया के रूप में स्थापित करती है, तो मास्टर के मरने पर अपने बच्चों को SITEUP इच्छाशक्ति (आसानी से) भेजी जाएगी। OTOH, प्रक्रियाएँ शायद ही कभी उस मुसीबत में जाती हैं - इसलिए मैं वास्तव में एक महत्वपूर्ण वक्रोक्ति को उठाने की तुलना में अधिक नाइट-पिकिंग हूं।
जोनाथन लेफलर

2
मैं कुछ घंटों के लिए इसके साथ बेवकूफ बना और काम करने के लिए इसे प्राप्त नहीं कर सका। यह अच्छी तरह से एक मामले को संभालेगा, जहां मेरे पास कुछ बच्चों के साथ एक डेमन है, जो कि माता-पिता के बाहर निकलने पर सभी को मरने की आवश्यकता होती है।
रोब के

1

यदि आप उदाहरण के लिए, pid 0 को संकेत भेजते हैं

kill(0, 2); /* SIGINT */

यह संकेत पूरी प्रक्रिया समूह को भेजा जाता है, इस प्रकार बच्चे को प्रभावी ढंग से मार देता है।

आप इसे आसानी से कुछ इस तरह से टेस्ट कर सकते हैं:

(cat && kill 0) | python

यदि आप ^ ^ D दबाते हैं, तो आप पाठ "Terminated"को एक संकेत के रूप में देखेंगे कि वास्तव में पायथन दुभाषिया को मार दिया गया है, इसके बजाय स्टैड बंद होने के कारण बाहर निकल गया है।


1
(echo -e "print(2+2)\n" & kill 0) | sh -c "python -" ख़ुशी
ख़त्म होने के

1

मामले में यह किसी और के लिए प्रासंगिक है, जब मैं सी ++ से कांटे की बाल प्रक्रियाओं में जेवीएम के उदाहरणों को देखता हूं, तो माता-पिता की प्रक्रिया पूरी होने के बाद मुझे जेवीएम के उदाहरण ठीक से समाप्त करने के लिए मिल सकते हैं। उम्मीद है कि कोई व्यक्ति टिप्पणियों में प्रतिक्रिया दे सकता है अगर यह ऐसा करने का सबसे अच्छा तरीका नहीं था।

1) prctl(PR_SET_PDEATHSIG, SIGHUP)जावा एप्लिकेशन लॉन्च करने से पहले सुझाए गए कांटेक्ट चाइल्ड प्रोसेस पर कॉल करें execv, और

2) जावा एप्लिकेशन में एक शटडाउन हुक जोड़ें जो तब तक मतदान करता है जब तक कि उसके माता-पिता पीआईडी ​​1 के बराबर नहीं हो जाते हैं, फिर एक कठिन काम करें Runtime.getRuntime().halt(0)। मतदान एक अलग शेल लॉन्च करके किया जाता है जो psकमांड चलाता है (देखें: मैं जावा में अपना पीआईडी ​​कैसे खोजूं या लिनक्स पर JRuby? )।

EDIT 130118:

ऐसा लगता है कि यह एक मजबूत समाधान नहीं था। मैं अभी भी थोड़ा सा संघर्ष कर रहा हूं कि क्या चल रहा है, इसकी बारीकियों को समझने के लिए, लेकिन स्क्रीन / एसएसएच सत्रों में इन अनुप्रयोगों को चलाते समय मुझे कभी-कभी अनाथ जेवीएम प्रक्रियाएं मिल रही थीं।

जावा ऐप में PPID के लिए मतदान करने के बजाय, मुझे बस शट डाउन हुक की सफाई करनी थी, जिसके बाद ऊपर एक कठिन पड़ाव आया। तब मैंने सुनिश्चित किया कि waitpidजब सब कुछ समाप्त होने का समय हो, तो स्पावर्ड चाइल्ड प्रोसेस पर C ++ पैरेंट ऐप में इनवॉइस करना सुनिश्चित करें । यह एक अधिक मजबूत समाधान प्रतीत होता है, क्योंकि बच्चे की प्रक्रिया यह सुनिश्चित करती है कि यह समाप्त हो जाए, जबकि अभिभावक मौजूदा सन्दर्भों का उपयोग करके यह सुनिश्चित करते हैं कि उसके बच्चे आगे बढ़ें। इसकी तुलना पिछले समाधान से करें, जब भी माता-पिता की प्रक्रिया समाप्त होती थी, जब भी वह प्रसन्न होता था, और बच्चों को यह पता लगाने की कोशिश करता था कि क्या उन्हें समाप्त करने से पहले अनाथ कर दिया गया था।


1
PID equals 1प्रतीक्षा मान्य नहीं है। नया अभिभावक कुछ अन्य पीआईडी ​​हो सकता है। आपको यह देखना चाहिए कि क्या यह मूल माता-पिता (फोर्क () से पहले) से नए पैरेंट (गेटपिड) में बदल जाता है, बच्चे में गेटपिड () जब फोर्क () से पहले कॉल नहीं किया जाता है)।
एलेक्सिस विल्के

1

लिनक्स विशिष्ट के लिए ऐसा करने का एक और तरीका यह है कि माता-पिता को एक नए पीआईडी ​​नामस्थान में बनाया जाए। इसके बाद उस नामस्थान में PID 1 होगा, और जब वह इसे बाहर निकालेगा तो सभी बच्चों को तुरंत मार दिया जाएगा SIGKILL

दुर्भाग्य से, एक नया पीआईडी ​​नाम स्थान बनाने के लिए आपके पास होना चाहिए CAP_SYS_ADMIN। लेकिन, यह विधि बहुत प्रभावी है और इसके लिए माता-पिता या बच्चों को प्रारंभिक लॉन्च से परे वास्तविक बदलाव की आवश्यकता नहीं है।

देखें क्लोन (2) , pid_namespaces (7) , और साझा करना बंद करें (2)


मुझे दूसरे तरीके से संपादित करने की आवश्यकता है। यह सभी बच्चों और पोते, और महान पोते, आदि के लिए एक प्रक्रिया प्रक्रिया के रूप में कार्य करने के लिए prctl का उपयोग करना संभव है ...
सर्वव्यापी

0

यदि माता-पिता की मृत्यु हो जाती है, तो अनाथों के पीपीआईडी ​​1 में बदल जाते हैं - आपको केवल अपने खुद के पीपीआईडी ​​की जांच करने की आवश्यकता होती है। एक तरह से, यह मतदान है, ऊपर वर्णित है। यहाँ उस के लिए खोल टुकड़ा है:

check_parent () {
      parent=`ps -f|awk '$2=='$PID'{print $3 }'`
      echo "parent:$parent"
      let parent=$parent+0
      if [[ $parent -eq 1 ]]; then
        echo "parent is dead, exiting"
        exit;
      fi
}


PID=$$
cnt=0
while [[ 1 = 1 ]]; do
  check_parent
  ... something
done

0

मुझे 2 समाधान मिले, दोनों सही नहीं हैं।

1. सभी बच्चों को मार डालो (-पिड) जब SIGTERM संकेत प्राप्त किया।
जाहिर है, यह समाधान "किल -9" को संभाल नहीं सकता है, लेकिन यह ज्यादातर मामलों के लिए काम करता है और बहुत सरल है क्योंकि इसे सभी बाल प्रक्रियाओं को याद रखने की आवश्यकता नहीं है।


    var childProc = require('child_process').spawn('tail', ['-f', '/dev/null'], {stdio:'ignore'});

    var counter=0;
    setInterval(function(){
      console.log('c  '+(++counter));
    },1000);

    if (process.platform.slice(0,3) != 'win') {
      function killMeAndChildren() {
        /*
        * On Linux/Unix(Include Mac OS X), kill (-pid) will kill process group, usually
        * the process itself and children.
        * On Windows, an JOB object has been applied to current process and children,
        * so all children will be terminated if current process dies by anyway.
        */
        console.log('kill process group');
        process.kill(-process.pid, 'SIGKILL');
      }

      /*
      * When you use "kill pid_of_this_process", this callback will be called
      */
      process.on('SIGTERM', function(err){
        console.log('SIGTERM');
        killMeAndChildren();
      });
    }

उसी तरह, आप 'एग्जिट' हैंडलर को उपरोक्त तरीके से स्थापित कर सकते हैं यदि आप कहीं कॉल करते हैं। नोट: Ctrl + C और अचानक क्रैश ओएस द्वारा स्वचालित रूप से प्रोसेस ग्रुप को मारने के लिए संसाधित किया गया है, इसलिए यहां और नहीं।

2.Use chjj / pty.js अपनी प्रक्रिया को नियंत्रित करने के लिए टर्मिनल संलग्न के साथ।
जब आप किसी भी तरह से -9 तक भी वर्तमान प्रक्रिया को मारते हैं, तो सभी बाल प्रक्रियाएं स्वचालित रूप से भी (ओएस द्वारा) मार दी जाएंगी। मेरा अनुमान है कि क्योंकि वर्तमान प्रक्रिया टर्मिनल का दूसरा पक्ष रखती है, इसलिए यदि वर्तमान प्रक्रिया मर जाती है, तो चाइल्ड प्रोसेस को SIGPIPE की मृत्यु हो जाएगी।


    var pty = require('pty.js');

    //var term =
    pty.spawn('any_child_process', [/*any arguments*/], {
      name: 'xterm-color',
      cols: 80,
      rows: 30,
      cwd: process.cwd(),
      env: process.env
    });
    /*optionally you can install data handler
    term.on('data', function(data) {
      process.stdout.write(data);
    });
    term.write(.....);
    */

0

मैं टर्मिनल नियंत्रण और सत्रों का दुरुपयोग करके 3 प्रक्रियाओं के साथ एक पोर्टेबल, गैर-मतदान समाधान करने में कामयाब रहा। यह मानसिक हस्तमैथुन है, लेकिन काम करता है।

चाल है:

  • प्रक्रिया A शुरू की गई है
  • प्रक्रिया A एक पाइप P बनाता है (और इससे कभी नहीं पढ़ता है)
  • प्रक्रिया ए कांटे प्रक्रिया बी में
  • प्रक्रिया बी एक नया सत्र बनाती है
  • प्रक्रिया B उस नए सत्र के लिए एक वर्चुअल टर्मिनल आवंटित करता है
  • प्रक्रिया B बच्चे के बाहर निकलने पर मरने के लिए SIGCHLD हैंडलर स्थापित करता है
  • प्रक्रिया B एक SIGPIPE हैंडलर सेट करता है
  • प्रक्रिया B प्रक्रिया C में कांटे बनाती है
  • प्रक्रिया C को जो कुछ भी आवश्यक है वह करता है (जैसे निष्पादन) अनमॉडिफाइड बाइनरी या जो भी तर्क चलाता है)
  • प्रक्रिया B पाइप P को लिखता है (और उस तरह से ब्लॉक करता है)
  • प्रक्रिया A प्रतीक्षा B () प्रक्रिया B पर समाप्त हो जाती है और मर जाने पर बाहर निकल जाती है

उस तरफ:

  • यदि प्रक्रिया A की मृत्यु हो जाती है: प्रक्रिया B एक SIGPIPE हो जाता है और मर जाता है
  • यदि प्रक्रिया B की मृत्यु हो जाती है: प्रक्रिया A की प्रतीक्षा () वापस आती है और मर जाती है, तो C को एक S नाईटअप मिल जाता है (क्योंकि जब टर्मिनल से जुड़े सत्र के सत्र के नेता की मृत्यु हो जाती है, तो अग्रभूमि प्रक्रिया समूह की सभी प्रक्रियाएँ SIGHUP हो जाती हैं)
  • यदि प्रक्रिया C की मृत्यु हो जाती है: प्रक्रिया B एक SIGCHLD हो जाती है और मर जाती है, इसलिए A की मृत्यु हो जाती है

कमियों:

  • प्रक्रिया C SIGHUP को संभाल नहीं सकती है
  • प्रक्रिया C को एक अलग सत्र में चलाया जाएगा
  • प्रक्रिया C सत्र / प्रक्रिया समूह API का उपयोग नहीं कर सकती क्योंकि यह भंगुर सेटअप को तोड़ देगा
  • ऐसे हर ऑपरेशन के लिए एक टर्मिनल बनाना सबसे अच्छा विचार नहीं है

0

हालांकि 7 साल बीत चुके हैं, मैं बस इस मुद्दे में भाग गया हूं क्योंकि मैं स्प्रिंगबूट एप्लिकेशन चला रहा हूं जिसे विकास के दौरान वेबपैक-देव-सर्वर शुरू करने की आवश्यकता है और बैकएंड प्रक्रिया बंद होने पर इसे मारने की जरूरत है।

मैं उपयोग करने की कोशिश करता हूं Runtime.getRuntime().addShutdownHookलेकिन यह विंडोज 10 पर काम करता है लेकिन विंडोज 7 पर नहीं।

मैंने इसे एक समर्पित थ्रेड का उपयोग करने के लिए बदल दिया है जो प्रक्रिया को छोड़ने के लिए इंतजार कर रहा है या InterruptedExceptionजिसके लिए दोनों विंडोज संस्करणों पर सही ढंग से काम करने लगता है।

private void startWebpackDevServer() {
    String cmd = isWindows() ? "cmd /c gradlew webPackStart" : "gradlew webPackStart";
    logger.info("webpack dev-server " + cmd);

    Thread thread = new Thread(() -> {

        ProcessBuilder pb = new ProcessBuilder(cmd.split(" "));
        pb.redirectOutput(ProcessBuilder.Redirect.INHERIT);
        pb.redirectError(ProcessBuilder.Redirect.INHERIT);
        pb.directory(new File("."));

        Process process = null;
        try {
            // Start the node process
            process = pb.start();

            // Wait for the node process to quit (blocking)
            process.waitFor();

            // Ensure the node process is killed
            process.destroyForcibly();
            System.setProperty(WEBPACK_SERVER_PROPERTY, "true");
        } catch (InterruptedException | IOException e) {
            // Ensure the node process is killed.
            // InterruptedException is thrown when the main process exit.
            logger.info("killing webpack dev-server", e);
            if (process != null) {
                process.destroyForcibly();
            }
        }

    });

    thread.start();
}

0

ऐतिहासिक रूप से, UNIX v7 से, प्रक्रिया प्रणाली ने एक प्रक्रिया 'पेरेंट आईडी' की जाँच करके प्रक्रियाओं की अनाथता का पता लगाया है। जैसा कि मैं कहता हूं, ऐतिहासिक रूप से, init(8)सिस्टम प्रक्रिया केवल एक कारण से एक विशेष प्रक्रिया है: यह मर नहीं सकता है। यह मर नहीं सकता है क्योंकि एक नई मूल प्रक्रिया आईडी असाइन करने से निपटने के लिए कर्नेल एल्गोरिथ्म, इस तथ्य पर निर्भर करता है। जब एक प्रक्रिया अपनी प्रक्रिया को निष्पादित करती है तो सिस्टम कॉल से पहले प्रक्रिया अनाथ हो गई।exit(2) कॉल को (एक प्रक्रिया प्रणाली कॉल के माध्यम से या बाहरी कार्य के रूप में इसे एक संकेत या इसी तरह भेजती है) तो कर्नेल इस प्रक्रिया के सभी बच्चों को उनके मूल प्रक्रिया आईडी के रूप में init प्रक्रिया के आईडी को पुन: असाइन करता है। यह सबसे आसान परीक्षण की ओर जाता है, और यह जानने का सबसे पोर्टेबल तरीका है कि क्या कोई प्रक्रिया अनाथ हो गई है। बस getppid(2)सिस्टम कॉल के परिणाम की जांच करें और यदि यह प्रक्रिया आईडी हैinit(2)

इस मुद्दे से दो मुद्दे उभर कर सामने आ सकते हैं:

  • सबसे पहले, हमारे पास initप्रक्रिया को किसी भी उपयोगकर्ता प्रक्रिया में बदलने की संभावना है , इसलिए हम कैसे आश्वस्त कर सकते हैं कि यह प्रक्रिया हमेशा सभी अनाथ प्रक्रियाओं का जनक होगी? ठीक है, exitसिस्टम कॉल कोड में यह देखने के लिए एक स्पष्ट जाँच है कि क्या कॉल को निष्पादित करने वाली प्रक्रिया एक init प्रक्रिया है (1 के बराबर पिड वाली प्रक्रिया) और यदि ऐसा है, तो कर्नेल पैनिक (इसे अब बनाए रखने में सक्षम नहीं होना चाहिए) प्रक्रिया पदानुक्रम) तो यह init प्रक्रिया के लिए एक exit(2)कॉल करने के लिए अनुमति नहीं है ।
  • दूसरा, ऊपर उजागर बुनियादी परीक्षा में एक दौड़ की स्थिति है। Init प्रक्रिया की आईडी को ऐतिहासिक रूप से माना जाता है 1, लेकिन यह POSIX दृष्टिकोण द्वारा वारंट नहीं किया गया है, यह बताता है कि (अन्य प्रतिक्रिया में उजागर) केवल एक सिस्टम की प्रक्रिया आईडी उस उद्देश्य के लिए आरक्षित है। लगभग कोई भी पॉज़िक्स कार्यान्वयन ऐसा नहीं करता है, और आप मूल यूनिक्स व्युत्पन्न सिस्टम में मान सकते हैं कि सिस्टम कॉल 1की प्रतिक्रिया के रूप में getppid(2)यह मानना ​​है कि प्रक्रिया अनाथ है। चेक करने का एक अन्य तरीका getppid(2)कांटा के ठीक बाद बनाना है और एक नए कॉल के परिणाम के साथ उस मूल्य की तुलना करना है। यह बस सभी मामलों में काम नहीं करता है, क्योंकि दोनों कॉल एक साथ परमाणु नहीं हैं, और fork(2)पहली getppid(2)प्रणाली कॉल के पहले और बाद में माता-पिता की प्रक्रिया मर सकती है । प्रक्रिया से parent id only changes once, when its parent does anबाहर निकलें (2) call, so this should be enough to check if theगेटपीड (2)result changed between calls to see that parent process has exit. This test is not valid for the actual children of the init process, because they are always children ofinit (8) `, लेकिन आप सुरक्षित रूप से इन प्रक्रियाओं को बिना माता-पिता के रूप में मान सकते हैं (सिवाय जब आप सिस्टम में प्रक्रिया के विकल्प के)

-1

मैंने बच्चे के लिए पर्यावरण का उपयोग करते हुए माता-पिता को पारित किया है, फिर समय-समय पर जांच की जाती है कि क्या / proc / $ ppid बच्चे से मौजूद है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.