2012-06-06 18 views
10

से बाल प्रक्रियाओं का उपयोग करना मेरे पास एक स्क्रिप्ट है जो बच्चों के एक समूह को जन्म देती है। माता-पिता को प्रत्येक बच्चे को खत्म करने की प्रतीक्षा करनी चाहिए।पर्ल

मेरे स्क्रिप्ट निम्नलिखित पर्ल स्क्रिप्ट के लिए इसी तरह करता है:

#! /usr/bin/perl 
use strict; 
use warnings; 

print "I am the only process.\n"; 

my @children_pids; 

for my $count (1..10){ 
     my $child_pid = fork(); 
     if ($child_pid) { # If I have a child PID, then I must be the parent 
       push @children_pids, $child_pid; 
     } 
     else { # I am the child 
       my $wait_time = int(rand(30)); 
       sleep $wait_time; 
       my $localtime = localtime; 
       print "Child: Some child exited at $localtime\n"; 
       exit 0; # Exit the child 
     } 
} 

foreach my $child (@children_pids) { 
     print "Parent: Waiting on $child\n"; 
     waitpid($child, 0); 
     my $localtime = localtime; 
     print "Parent: Child $child was reaped - $localtime.\n"; 
} 

print "All done.\n"; 

कोड मैं ऊपर प्रदान की है की तरह, प्रत्येक बच्चे को एक अलग समय लग सकता है समाप्त करने के लिए।

समस्या यह है कि जब मैं बच्चों को पीआईडी ​​पर लूप करके बच्चों को काटने की कोशिश करता हूं, उस अंतिम foreach ब्लॉक में, माता-पिता बच्चों के आदेश के क्रम में इंतजार कर रहे हैं।

स्पष्ट रूप से बच्चे जो क्रमशः उत्पन्न होते हैं, वे खत्म नहीं होते हैं और इसलिए मुझे जल्दी खत्म होने वाले बच्चों के लिए ज़ोंबी प्रक्रियाओं का एक गुच्छा छोड़ दिया जाता है।

मेरे वास्तविक कोड में, ये बच्चे एक दूसरे से पहले दिन खत्म कर सकते हैं और सैकड़ों में चारों ओर तैरने वाली ज़ोंबी प्रक्रियाओं की संख्या बढ़ सकती है।

क्या बच्चों के एक समूह काटने के लिए मेरे लिए एक बेहतर तरीका है?

उत्तर

12

अपने माता पिता की प्रक्रिया अपने बच्चों के पूरा होने की स्थिति के बारे में पता होना करने के लिए की जरूरत नहीं है, तो आप सिर्फ

$SIG{CHLD} = 'IGNORE'; 

जो स्वचालित रूप से सभी बच्चों के रूप में वे पूरा काटेंगे सेट कर सकते हैं।

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

use POSIX(); 

$SIG{CHLD} = sub { 
    while() { 
    my $child = waitpid -1, POSIX::WNOHANG; 
    last if $child <= 0; 
    my $localtime = localtime; 
    print "Parent: Child $child was reaped - $localtime.\n"; 
    } 
}; 
+1

सूचित करने का प्राथमिक कारण: यह देखने के लिए कि वे सफल थे या नहीं। – ikegami

+0

हे बोरोडिन, चेक आउट करें [सिंटेक्स :: फ़ीचर :: लूप] (http://search.cpan.org/perldoc?Syntax:: फीचर :: लूप) – ikegami

+0

@ikegami: हाँ मैं कभी-कभी इसका उपयोग करता हूं। मैं ज्यादातर 'जबकि (1) ',' जबकि() 'और' {... फिर से उपयोग करने के बीच में फिसल जाता हूं; } '। कोई भी वास्तव में संतोषजनक नहीं है। – Borodin

6

पिड के लिए "-1" का उपयोग करें, या प्रतीक्षा() फ़ंक्शन का उपयोग करें ताकि आप किसी भी बच्चे की प्रक्रिया की प्रतीक्षा कर सकें। रीपड पिड वापस कर दिया जाता है, इसलिए यदि आवश्यक हो तो आप इसे अपनी सूची के विरुद्ध देख सकते हैं। यदि यह अस्वीकार्य है, तो दूसरी सूची के रूप में POSIX :: WNOHANG() के साथ आपकी सूची में प्रत्येक पिड के लिए समय-समय पर प्रतीक्षा करें।

5

Borodin's answer वे के रूप में बच्चों के अतुल्यकालिक कटाई के लिए बिल्कुल ठीक है काटते करने के लिए निर्धारित करने की आवश्यकता समाप्त।

के रूप में अपने प्रश्न और कोड मेरे लिए सुझाव देते हैं, आप देख रहे हैं, तो तुल्यकालिक (अवरुद्ध) के लिए सभी बकाया बच्चों जिसमें वे समाप्त की उठा, माता पिता के बस यह कर सकते हैं:

use feature qw(say); 

... 

# Block until all children are finished 
while (1) { 
    my $child = waitpid(-1, 0); 
    last if $child == -1;  # No more outstanding children 

    say "Parent: Child $child was reaped - ", scalar localtime, "."; 
} 

say "All done." 
1

कभी बच्चों के लिए प्रतीक्षा करने के लिए इस तरह एक पाश का उपयोग करें: जबकि मरने के लिए बच्चे की प्रक्रिया के लिए इंतजार

while (1) { 
    my $child = waitpid(-1, POSIX::WNOHANG); 
    last if $child == -1; 
    print "Parent: Child $child was reaped\n"; 
} 

माता पिता प्रक्रिया 100% CPU की खपत होगी - ई खासकर जब वे लंबे समय तक दौड़ सकते हैं। कम से कम एक नींद जोड़ें (बुरा विचार - जब वे तेजी से मर जाते हैं, तो माता-पिता प्रतीक्षा कर रहे हैं)।

हमेशा एक अवरुद्ध इंतजार का उपयोग + संतोषप्रदता !:

my $loop = 1; 
$SIG{CHLD} = 'DEFAULT'; # turn off auto reaper 
$SIG{INT} = $SIG{TERM} = sub {$loop = 0; kill -15 => @children_pids}; 
while ($loop && getppid() != 1) { 
    my $child = waitpid(-1, 0); 
    last if $child == -1; 
    print "Parent: Child $child was reaped\n"; 
} 

के लिए सावधि/INT/ppid के लिए गिनती यह अवरुद्ध पाठ्यक्रम संभव नहीं की यह इंतजार जब जनक प्रक्रिया भी अन्य सामान करना है - getppid की तरह() कॉल ;-)।इसके लिए, आप सॉकेटपेयर() का उपयोग कर सकते हैं और इसे एक चुनिंदा() में डाल सकते हैं जो अवरुद्ध कॉल करता है। यहां तक ​​कि लूप जांच भी इससे लाभ उठा सकती है।

+0

यह हमेशा के लिए लूप नहीं होना चाहिए, यही 'आखिरी अगर' लाइन करता है। अगर कोई बच्चा मर गया है, तो यह लूप से बाहर निकलता है। –

+0

यह हमेशा के लिए लूपिंग के बारे में नहीं है, यह लूपिंग के दौरान उपयोग किए जाने वाले 100% सीपीयू चक्रों के बारे में है। यदि 200 प्रक्रियाओं के अंत में 10 मिनट लगते हैं, तो यह 10 मिनट के लिए 100% सीपीयू चक्र बर्बाद करने की प्रक्रिया है, जबकि यदि आप ब्लॉक करते हैं, तो यह मूल रूप से कोई नहीं है। – CowboyTim