2008-12-04 9 views
13

कृपया निम्नलिखित fork()/SIGCHLD छद्म कोड पर विचार करें।एक कांटा()/SIGCHLD दौड़ की स्थिति से बचें

// main program excerpt 
    for (;;) { 
     if (is_time_to_make_babies) { 

     pid = fork(); 
     if (pid == -1) { 
      /* fail */ 
     } else if (pid == 0) { 
      /* child stuff */ 
      print "child started" 
      exit 
     } else { 
      /* parent stuff */ 
      print "parent forked new child ", pid 
      children.add(pid); 
     } 

     } 
    } 

    // SIGCHLD handler 
    sigchld_handler(signo) { 
    while ((pid = wait(status, WNOHANG)) > 0) { 
     print "parent caught SIGCHLD from ", pid 
     children.remove(pid); 
    } 
    } 

उपर्युक्त उदाहरण में रेस-हालत है। "/* child stuff */" से पहले समाप्त होना संभव है "/* parent stuff */" शुरू होता है जिसके परिणामस्वरूप बच्चे के पिड को बाहर निकलने के बाद बच्चों की सूची में जोड़ा जा सकता है, और कभी भी हटाया नहीं जा सकता है। जब ऐप बंद होने के लिए समय आता है, तो माता-पिता पहले से समाप्त होने वाले बच्चे को समाप्त होने के लिए अंतहीन रूप से इंतजार करेंगे।

एक समाधान मैं इसका सामना करने के बारे में सोच सकता हूं कि इसमें दो सूचियां हों: started_children और finished_children। मैं उसी स्थान पर started_children में जोड़ूंगा जो मैं अब children में जोड़ रहा हूं। लेकिन सिग्नल हैंडलर में, children से हटाने की बजाय मैं finished_children जोड़ सकता हूं। जब ऐप बंद हो जाता है, तो माता-पिता बस started_children और finished_children के बीच अंतर शून्य तक प्रतीक्षा कर सकते हैं।

एक और संभावित समाधान जो मैं सोच सकता हूं साझा साझा स्मृति का उपयोग कर रहा है, उदा। बच्चों की माता-पिता की सूची साझा करें और बच्चों को .add और .remove स्वयं को दें? लेकिन मुझे इसके बारे में बहुत कुछ पता नहीं है।

संपादित करें: एक और संभावित समाधान, जो पहली बात थी, ध्यान में रखकर, sleep(1) को /* child stuff */ की शुरुआत में जोड़ना है, लेकिन यह मेरे लिए मजाकिया है, इसलिए मैंने इसे छोड़ दिया। मुझे यह भी यकीन नहीं है कि यह 100% तय है।

तो, आप इस दौड़-स्थिति को कैसे ठीक करेंगे? और यदि इसके लिए एक अच्छी तरह से स्थापित अनुशंसित पैटर्न है, तो कृपया मुझे बताएं!

धन्यवाद।

+0

क्या यह सिर्फ मुझे है या सिग्नल हैंडलर असिंक-सुरक्षित नहीं है? बच्चों को कैसे हटाया जा सकता है .remove() संभवतः विस्फोट करने के लिए लागू किया जा सकता है जब एक नया सिग्लड मध्य में इसे बाधित करता है? –

उत्तर

15

सरल समाधान fork()sigprocmask() के साथ SIGCHLD सिग्नल को अवरुद्ध करना होगा और पिड को संसाधित करने के बाद इसे मूल कोड में अनब्लॉक करना होगा।

यदि बच्चे की मृत्यु हो गई है, तो सिग्नल को अनवरोधित करने के बाद सिगचल के लिए सिग्नल हैंडलर को बुलाया जाएगा। यह एक महत्वपूर्ण खंड अवधारणा है - आपके मामले में महत्वपूर्ण अनुभाग fork() से पहले शुरू होता है और children.add() के बाद समाप्त होता है।

+0

के बीच है, मुझे यह समाधान पसंद है। दुर्भाग्य से मैं इसे PHP में कर रहा हूं और अभी तक एक रिलीज में कोई sigprocmask() नहीं है :(यह सीवीएस में है, हालांकि यह केवल समय की बात है। मुझे जानकारी के लिए धन्यवाद। शायद मुझे इसके लिए एक अलग भाषा का उपयोग करना चाहिए प्रोजेक्ट - कोई सेटप्रोक्टीटल() - PHP में समान रूप से ऐसा लगता है। –

-1

मौजूदा "बच्चों" के अतिरिक्त एक नई डेटा संरचना "प्रारंभिक मौत" जोड़ें। यह बच्चों की सामग्री को साफ रखेगा।

// main program excerpt 
    for (;;) { 
     if (is_time_to_make_babies) { 

     pid = fork(); 
     if (pid == -1) { 
      /* fail */ 
     } else if (pid == 0) { 
      /* child stuff */ 
      print "child started" 
      exit 
     } else { 
      /* parent stuff */ 
      print "parent forked new child ", pid 
      if (!earlyDeaths.contains(pid)) { 
       children.add(pid); 
      } else { 
       earlyDeaths.remove(pid); 
      } 
     } 

     } 
    } 

    // SIGCHLD handler 
    sigchld_handler(signo) { 
    while ((pid = wait(status, WNOHANG)) > 0) { 
     print "parent caught SIGCHLD from ", pid 
     if (children.contains(pid)) { 
      children.remove(pid); 
     } else { 
      earlyDeaths.add(pid); 
     } 
    } 
    } 

संपादित करें: अगर आपके प्रक्रिया एकल लड़ी है इस सरल किया जा सकता - earlyDeaths एक कंटेनर होना जरूरी नहीं है, यह सिर्फ एक पीआईडी ​​धारण करने के लिए है।

+0

यह वास्तव में दौड़ की स्थिति को हल नहीं करता है - बच्चा मर सकता है जबकि माता-पिता 'if (! प्रारंभिकताएं। कॉन्टैन्स (पिड))' और 'children.add (pid)' – qrdl

0

यदि आप महत्वपूर्ण टुकड़े का उपयोग नहीं कर सकते हैं, तो शायद एक साधारण काउंटर यह काम कर सकता है। +1 जोड़ने पर, -1 हटाते समय, कोई मेटर जो पहले होता है, अंततः आप शून्य हो सकते हैं जब सब कुछ किया जाता है।

-1

शायद एक आशावादी एल्गोरिदम? बच्चों को आज़माएं। रिमूव (पिड), और यदि यह विफल रहता है, तो जीवन के साथ आगे बढ़ें।

या जांचें कि इसे निकालने का प्रयास करने से पहले उस पिड बच्चों में है?

 संबंधित मुद्दे

  • कोई संबंधित समस्या नहीं^_^