2009-05-26 3 views
10

Ben basitleştirmek için birden çok parametre için bir shell script çalıştırır bazı Perl kodu, var, ben sadece şuna benzer bir kod olduğunu varsayıyoruz:Çocuk süreçlerinin sistem() ile arka planda başlatılmasını Perl bekle nasıl yapabilirim?

for $p (@a){ 
    system("/path/to/file.sh $p&"); 
} 

ben sonra biraz daha fazla şeyler yapmak istiyorum Bu, ancak devam etmeden önce tüm çocuk süreçlerinin bitmesini beklemenin bir yolunu bulamıyorum.

Kullanılacak kodu fork() dönüştürmek zor olacaktır. Daha kolay bir yolu yok mu?

+0

Dosyadan gerçek dönüş kodunu istiyor musunuz? Komut dosyasını, tamamlandığında bir dosyaya yazacak şekilde değiştirebilir misiniz? – mkb

+1

Neden kodu çatalı dönüştürmek zor olur? Bir alt yordamdaki tüm ayrıntıları gizle. Bunun yerine, sisteminizi() yeni alt yordamınızı çağırmak için yeniden tanımlayabilirsiniz. –

+0

Muhtemelen bu parçayı forking yapan ayrı bir betiğe bölüşeceğim ve sistem çağrısından bunu çağıracağım… –

cevap

16

/exec/wait çok kötü değil:

my @a = (1, 2, 3); 
for my $p (@a) { 
    my $pid = fork(); 
    if ($pid == -1) { 
     die; 
    } elsif ($pid == 0) { 
     exec '/bin/sleep', $p or die; 
    } 
} 
while (wait() != -1) {} 
print "Done\n"; 
+1

Hatalı bir çatalı kontrol etmiyorsunuz ve porsiyonun pidine $ pid değil, @pids'e bastırıyorsunuz. Çıkış muhtemelen bir kalıp olmalıdır, eğer yürütülürse exec başarısız oldu demektir. –

+0

Sabit. Teşekkürler, ben aslında Perl'in ana konuşmacısı değilim. – Dave

+0

$ pid == -1, bunun yerine muhtemelen tanımlanmış ($ pid) olmalıdır. –

8

Çatalla() dönüştürmek zor olabilir, ancak bu doğru bir araçtır. sistem() bir engelleme çağrısıdır; Bir kabuk yürütmek ve komut dosyalarınızı arka planda çalıştırmak için bunu söyleyerek engelleme dışındaki davranışları alıyorsunuz. Bu, Perl'in çocukların PID'lerinin ne olabileceği hakkında hiçbir fikri olmadığı anlamına gelir, bu da komut dosyanızın ne beklemesi gerektiğini bilmez.

PID'leri Perl komut dosyasına kadar iletmeyi deneyebilirsiniz, ancak bu hızlı bir şekilde elden çıkar. Çatal() kullanın.

13

Bir şeyi değiştirmeniz gerekecek, çatal kullanmak için kodu değiştirmeniz muhtemelen daha basittir, ancak çatal kullanmaya karşı ölü olarak ayarlanmışsanız, dosya bittiğinde dosyaya dokunan sarıcı kabuk komut dosyası kullanabilirsiniz. Perl kodunuzun dosyaların varlığını kontrol etmesini sağlayın.

#!/bin/bash 

$* 

touch /tmp/$2.$PPID 

Kişisel Perl kodu gibi görünecektir::

for my $p (@a){ 
    system("/path/to/wrapper.sh /path/to/file.sh $p &"); 
} 
while (@a) { 
    delete $a[0] if -f "/tmp/$a[0].$$"; 
} 

Ama çatallaşma kodu daha güvenli ve daha net olduğunu düşünüyorum: Burada

sarıcı çatal kullanma

my @pids; 
for my $p (@a) { 
    die "could not fork" unless defined(my $pid = fork);\ 
    unless ($pid) { #child execs 
     exec "/path/to/file.sh", $p; 
     die "exec of file.sh failed"; 
    } 
    push @pids, $pid; #parent stores children's pids 
} 

#wait for all children to finish 
for my $pid (@pids) { 
    waitpid $pid, 0; 
} 
+0

Bu daha iyi bir cevap. – zdim

+0

Görünüşe göre, bu çok fazla zombi süreci yaratıyor. https://en.wikipedia.org/wiki/Zombie_process –

+1

@PratyushRathore Olmamalıdır. Ebeveyn süreci beklemediğinde veya beklemediğinde bir zombi oluşur. Gördüğünüz gibi ebeveyn, çıkmış bir çocuk için waitpid çağırıyor. Eğer bir grup zombi alıyorsanız, ya yanlış bir şey yapıyorsunuz ya da ilk çocuklardan biri uzun bir zaman alıyor ve daha sonraki çocuklar çıkmış oluyorlar (ama hiç karşılaşmadılar). Bir sonraki çıkış çocuğunu almak için while (waitpid (-1, WNOHANG)> 0) {sleep 1} 'konumuna geçebilirsiniz. –

İlgili konular