2016-08-02 4 views
5

मेरे पास एक लंबे समय से चलने वाला प्रोग्राम है जो अस्थायी फ़ाइल बनाने के लिए File::Temp::tempdir का उपयोग करता है और कभी-कभी ^C के माध्यम से इसे बाधित करता है।पर्ल में ईएनडी ब्लॉक किस स्थिति में छोड़ दिए गए हैं?

निम्न प्रोग्राम उस अस्थायी निर्देशिका के नाम को प्रिंट करता है और इसमें फ़ाइल का नाम प्रिंट करता है।

#!/usr/bin/env perl 
use strict; 
use warnings; 
use File::Temp qw[tempdir]; 

my $dir = tempdir(CLEANUP => 1); 
print "$dir\n"; 
print "$dir/temp.txt\n"; 

`touch $dir/temp.txt`; 
exit; 

OS X पर, इस के अंदर /var/folders

एक निर्देशिका बनाता है अंतिम पंक्ति exit; या die; है, तो फ़ोल्डर साफ हो जाएगी और इसके अंदर अस्थायी फ़ाइल हटा दिया जाता है जाएगा।

हालांकि, अगर हम sleep 20; के साथ अंतिम पंक्ति को प्रतिस्थापित करते हैं और फिर ^C के माध्यम से perl प्रोग्राम को बाधित करते हैं, तो अस्थायी निर्देशिका बनी हुई है।

% perl maketemp.pl 
/var/folders/dr/cg4fl5m11vg3jfxny3ldfplc0000gn/T/ycilyLSFs6 
/var/folders/dr/cg4fl5m11vg3jfxny3ldfplc0000gn/T/ycilyLSFs6/temp.txt 
^C 
% stat /var/folders/dr/cg4fl5m11vg3jfxny3ldfplc0000gn/T/ycilyLSFs6/temp.txt 
16777220 6589054 -rw-r--r-- 1 <name> staff 0 0 "Aug 1 20:46:27 2016" "Aug 1 20:46:27 2016" "Aug 1 20:46:27 2016" "Aug 1 20:46:27 2016" 4096 0 0 
/var/folders/dr/cg4fl5m11vg3jfxny3ldfplc0000gn/T/ycilyLSFs6/temp.txt 
% 
एक संकेत हैंडलर कि सिर्फ कॉल exit; निर्देशिका को साफ करता है का उपयोग कर

। जैसे

#!/usr/bin/env perl 
use strict; 
use warnings; 
use File::Temp qw[tempdir]; 

$SIG{INT} = sub { exit; }; 

my $dir = tempdir(CLEANUP => 1); 
print "$dir\n"; 
print "$dir/temp.txt\n"; 

`touch $dir/temp.txt`; 
sleep 20; 

के रूप में निर्धारित करने के लिए कैसे tempdir एक सफाई कार्रवाई

यहाँ दर्ज की है एक "तुच्छ" संकेत हैंडलर

#!/usr/bin/env perl 
use strict; 
use warnings; 
use File::Temp qw[tempdir]; 

$SIG{INT} = sub { }; 

my $dir = tempdir(CLEANUP => 1); 
print "$dir\n"; 
print "$dir/temp.txt\n"; 

`touch $dir/temp.txt`; 
sleep 20; 

मैं स्रोत कोड (https://github.com/Perl-Toolchain-Gang/File-Temp/blob/master/lib/File/Temp.pm) के माध्यम से देख कोशिश का उपयोग कर करता है बाहर निकलें हैंडलर है स्थापना

https://github.com/Perl-Toolchain-Gang/File-Temp/blob/master/lib/File/Temp.pm#L1716

जो _deferred_unlink

https://github.com/Perl-Toolchain-Gang/File-Temp/blob/master/lib/File/Temp.pm#L948

जो वैश्विक हैश %dirs_to_unlink और %files_to_unlink संशोधित कहता है, लेकिन किसी कारण (शायद मामले में पर्ल दुभाषिया कांटे के लिए एक प्रमुख के रूप में पीआईडी ​​$$ का उपयोग करता है? निश्चित नहीं है कि यह क्यों जरूरी है कि एक निर्देशिका को हटाने के बाद ऐसा लगता है कि यह एक बेवकूफ ऑपरेशन होगा।)

फाइलों को साफ करने के लिए वास्तविक तर्क END ब्लॉक में है।

https://github.com/Perl-Toolchain-Gang/File-Temp/blob/master/lib/File/Temp.pm#L878

एक त्वरित प्रयोग कि END ब्लॉक वास्तव में चलाए जा रहे हैं जब पर्ल सामान्य रूप से या असामान्य रूप से बाहर निकल गया है पता चलता है।

sleep 20; 

END { 
    print "5\n"; 
} 

# does not print 5 when interrupted 

और यहाँ

$SIG{INT} = sub {}; 
sleep 20; 

END { 
    print "5\n"; 
} 

# does print 5 when interrupted 

चलाए जा रहे हैं तो ... क्यों END ब्लॉक प्राप्त जब तक कि वहाँ एक संकेत हैंडलर है, यहां तक ​​कि एक ही है कि यह की तरह लगता है कुछ नहीं करना है एक SIGINT के बाद छोड़ दिया है?

+0

'नींद (20);' नींद (20) या चेतावनी ($!) के साथ '' नींद (20); प्रिंट ("पूर्ण \ n"); ' – ikegami

उत्तर

6

डिफ़ॉल्ट रूप से, SIGINT प्रक्रिया [1] को मारता है। मारने से, मेरा मतलब है कि प्रक्रिया को तुरंत कर्नेल द्वारा समाप्त कर दिया जाता है। प्रक्रिया किसी भी सफाई करने के लिए नहीं मिलता है।

सिगिनट के लिए हैंडलर सेट करके, आप इस व्यवहार को ओवरराइड करते हैं। प्रक्रिया को मारने के बजाय, सिग्नल हैंडलर को बुलाया जाता है। यह कुछ भी नहीं कर सकता है, लेकिन इसके अस्तित्व ने प्रक्रिया को मारने से रोका। इस स्थिति में, कार्यक्रम संकेत की वजह से बाहर निकल जाएगा नहीं जब तक कि यह (die या exit हैंडलर में फोन करके बाहर निकलने के लिए चुनता है। यदि ऐसा है, तो यह सामान्य रूप सफाई करने का मौका मिलेगा।

नोट कि यदि एक सिग्नल जिसके लिए एक हैंडलर परिभाषित किया गया था, सिस्टम कॉल के दौरान आता है, तो प्रोग्राम कॉल को सुरक्षित रूप से सिग्नल को संभालने की अनुमति देने के लिए त्रुटि EINTR के साथ निकलती है। यही कारण है कि sleep जैसे ही सिगिनट प्राप्त होता है।

यदि इसके बजाय आपने $SIG{INT} = 'IGNORE'; का उपयोग किया था, तो सिग्नल पूरी तरह से अनदेखा कर दिया गया था। प्रगति पर आने वाले किसी भी सिस्टम में बाधा नहीं डाली जाएगी।


  1. मेरे सिस्टम पर, man 1 kill संकेतों के डिफ़ॉल्ट कार्यों को सूचीबद्ध करता है।
4

आपका सिग्नल हैंडलर $SIG{INT} = sub {} कुछ भी नहीं कर रहा है, यह सिग्नल फंस रहा है और प्रोग्राम को बाहर निकलने से रोक रहा है।

लेकिन अपने मूल प्रश्न, END ब्लॉक जवाब देने के लिए, perlmod के रूप में कहते हैं:

, के रूप में देर से संभव के रूप में क्रियान्वित किया जाता है वह यह है कि, के बाद पर्ल कार्यक्रम और बस से पहले दुभाषिया से बाहर निकल गया की जा रही है चलना समाप्त कर दिया, भले ही यह मरने() फ़ंक्शन के परिणामस्वरूप बाहर निकल रहा हो। (लेकिन नहीं अगर यह कार्यकारी के माध्यम से एक अन्य कार्यक्रम में morphing की गई है या संकेत द्वारा पानी से बाहर उड़ा जा रहा है -। आप जाल करने के लिए है कि अपने आप को (यदि आप कर सकते हैं))

यही है, एक घातक संकेत, अगर फंस नहीं पड़ता है, तो पर्ल के वैश्विक विनाश को रोकता है और END ब्लॉक को कॉल नहीं करता है।

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