2011-01-20 10 views
8

मैं कांटा पर कुछ सरल कोड देख रहा था, और इसे अपने लिए कोशिश करने का फैसला किया। मैंने संकलित किया और फिर इसे इमाक्स के अंदर से चलाया, और बैश में इसे चलाने से उत्पादित उस आउटपुट में एक अलग आउटपुट मिला।जब मैं अपना आउटपुट पाइप करता हूं तो मेरे फोर्किंग प्रोग्राम का आउटपुट अलग क्यों होता है?

#include <unistd.h> 
#include <stdio.h> 

int main() { 
    if (fork() != 0) { 
    printf("%d: X\n", getpid()); 
    } 

    if (fork() != 0) { 
    printf("%d: Y\n", getpid()); 
    } 

    printf("%d: Z\n", getpid()); 
} 

मैं जीसीसी के साथ संकलित, और उसके बाद Emacs अंदर से a.out भाग गया है, साथ ही cat, और grep . को यह पाइप, और इस मिला है।

2055: एक्स
2055: वाई
2055: जेड
2055: एक्स
2058: जेड
2057: वाई
2057: जेड
2059: जेड

यह सही नहीं है। यह सिर्फ बैश से चल रहा है मैं (जो मैं उम्मीद)

2084: एक्स
2084: वाई
2084: जेड
2085: वाई
2085: जेड
2087: जेड
2086: जेड

संपादित करें - कुछ नई पंक्तियां याद

क्या चल रहा है?

+0

आप कुछ भी के माध्यम से परिणाम क्यों पाइप कर रहे हैं (esp। "Cat" जो वास्तव में कुछ भी नहीं करेगा)? - ओह प्रतीक्षा करें यह पाइपिंग है जो विषमता को पेश करता है ... हम्म ... – Pointy

+0

मैं इसे पुन: पेश कर सकता हूं, इसलिए यह ब्रह्मांडीय किरण या कुछ भी नहीं है। पेचीदा। ध्यान दें कि पूर्व आउटपुट में एक पीआईडी ​​(2056) गायब है; शायद यह 'बिल्ली' का पीआईडी ​​है। – Thomas

+0

मैंने इसे कुछ बार चलाया, जिनमें से अधिकांश में पीआईडी ​​गायब नहीं था। – Squidly

उत्तर

11

ऑर्डर जिसमें विभिन्न प्रक्रियाएं उनके आउटपुट को लिखती हैं पूरी तरह से अप्रत्याशित है। तो एकमात्र आश्चर्य यह है कि कभी-कभी "एक्स" प्रिंट स्टेटमेंट कभी-कभी दो बार होता है।

मेरा मानना ​​है कि ऐसा इसलिए होता है क्योंकि कभी-कभी दूसरे fork() पर, "एक्स" समेत एक आउटपुट लाइन आउटपुट बफर में होती है, जिसे फ़्लश करने की आवश्यकता होती है। इसलिए दोनों प्रक्रियाएं अंततः इसे प्रिंट करती हैं। चूंकि getpid() को पहले से ही बुलाया गया था और स्ट्रिंग में परिवर्तित किया गया था, इसलिए वे एक ही पिड दिखाएंगे।

मैं कई "एक्स" लाइनों को पुन: पेश करने में सक्षम था, लेकिन अगर मैं fflush(stdout); को दूसरे fork() से पहले जोड़ता हूं, तो मैं हमेशा केवल एक "एक्स" रेखा और हमेशा कुल 7 लाइनों को देखता हूं।

8

मुझे लगता है कि मुझे पता है कि क्या हो रहा है। आउटपुट एक टीटी बनाम जब एक पाइप या फ़ाइल है, तो stdio बफरिंग अलग हो जाएगा। बच्चे की प्रक्रिया माता-पिता बफर का उत्तराधिकारी होती है। जब वे फ्लश हो जाते हैं, तो आप डबल आउटपुट प्राप्त कर सकते हैं।

आप सही प्रत्येक printf() कॉल के बाद

fflush(stdout); 

जोड़ते हैं तो आपको मैं क्या मतलब देखेंगे।

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

+0

दरअसल! प्रत्येक 'printf' के बाद इसे हल करने के बाद' fflush (stdout) डालना; आउटपुट बफर की सामग्री कांटा के समय कॉपी की जाती है, इसलिए बफर फ़्लश होने पर वही buffered आउटपुट दो बार मुद्रित हो जाता है। – Thomas

+0

यह सही है। एक इंटरैक्टिव टर्मिनल पर लिखते समय 'stdout' डिफ़ॉल्ट रूप से लाइन-बफर किया जाता है (इसलिए प्रत्येक' \ n' के बाद फ़्लश किया जाता है), लेकिन पाइप पर लिखते समय पूरी तरह से buffered किया जाता है। एक 'एफएफएलयूएस (स्टडआउट);' प्रत्येक 'कांटा()' से पहले भी काम करेगा। – caf

6

तो मुझे कल्पना है कि आप सोच रहे हैं कि आपको एक से अधिक "एक्स" क्यों मिल रहे हैं?

ऐसा इसलिए है क्योंकि buffered आउटपुट दो बार फ़्लश किया जा रहा है।

जब आप किसी प्रोग्राम के आउटपुट को पाइप करते हैं, तो stdio लाइब्रेरी पहचानती है कि आपका आउटपुट टर्मिनल नहीं है, और यह लाइन बफरिंग के बजाए बफरिंग को अवरुद्ध करने के लिए स्विच करता है। नतीजतन, अभी तक कोई आउटपुट नहीं है जब प्रक्रिया कांटे और अब दोनों माता-पिता और बच्चे के पास आउटपुट लंबित है।

3

आप stdout का इस्तेमाल किया है, तो सब पर forking पहले, आप चाहिए कॉल fflush(stdout)fork() से पहले (और इसी तरह किसी अन्य उत्पादन FILE रों आप उपयोग के लिए)। ऐसा करने में विफलता अपरिभाषित व्यवहार में परिणाम। आप जिस प्रभाव को देख रहे हैं वह stdoutलाइन-बफर्ड से टर्मिनल से कनेक्ट होने पर आता है, लेकिन पूरी तरह से को पाइप से कनेक्ट होने पर पूरी तरह से buffered किया जाता है। यह आवश्यक नहीं है, लेकिन मानकों (POSIX) द्वारा अनुशंसित।