2012-07-31 9 views
28

"यूनिक्स पर्यावरण में उन्नत प्रोग्रामिंग", द्वितीय संस्करण, डब्ल्यू रिचर्ड स्टीवंस द्वारा।कोई भी फोर्क() के बाद 'फ़ाइल डिस्क्रिप्टर' के बारे में एक सरल विवरण समझा सकता है?

धारा 8.3 कांटा समारोह।

यह महत्वपूर्ण है माता-पिता और बच्चे ऑफसेट एक ही फाइल का हिस्सा है कि:

यहाँ विवरण दिया गया है।

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

[1। इसका क्या मतलब है? अगर माता-पिता के std आउटपुट को 'file1' पर रीडायरेक्ट किया गया है, तो बच्चे के लिखने के बाद बच्चे को क्या अपडेट करना चाहिए? माता-पिता का मूल std आउटपुट ऑफसेट या रीडायरेक्ट आउटपुट (i.e file1) ऑफसेट? बाद में नहीं हो सकता है, है ना?]

[2। अपडेट कैसे किया जाता है? बच्चे द्वारा स्पष्ट रूप से, ओएस द्वारा निस्संदेह, फाइल डिस्क्रिप्टर द्वारा स्वयं? कांटा के बाद, मैंने सोचा कि माता-पिता और बच्चे अपने तरीके से गए हैं और फ़ाइल डिस्क्रिप्टर की अपनी कॉपी है। तो बच्चे को मूल पक्ष में ऑफसेट कैसे अपडेट किया जाता है?]

इस मामले में, बच्चे मानक आउटपुट पर लिख सकता है जबकि माता-पिता इसके लिए प्रतीक्षा कर रहे हैं; बच्चे के पूरा होने पर, माता-पिता मानक आउटपुट में लिखना जारी रख सकते हैं, यह जानकर कि उसके आउटपुट को बच्चे द्वारा लिखे गए किसी भी चीज़ में जोड़ा जाएगा। यदि माता-पिता और बच्चे ने एक ही फ़ाइल ऑफसेट साझा नहीं किया है, तो इस प्रकार की बातचीत को पूरा करना अधिक कठिन होगा और माता-पिता द्वारा स्पष्ट कार्रवाइयों की आवश्यकता होगी।

यदि माता-पिता और बच्चे दोनों एक ही डिस्क्रिप्टर को लिखते हैं, बिना सिंक्रनाइज़ेशन के किसी भी प्रकार के, जैसे माता-पिता बच्चे के लिए प्रतीक्षा करते हैं, तो उनका आउटपुट इंटरमीक्स किया जाएगा (माना जाता है कि यह एक वर्णक है जो कांटा से पहले खुला था)। हालांकि यह संभव है, यह ऑपरेशन का सामान्य तरीका नहीं है।

एक कांटा के बाद वर्णनकर्ताओं को संभालने के लिए दो सामान्य मामले हैं।

  1. माता-पिता बच्चे को पूरा करने की प्रतीक्षा करता है। इस मामले में, माता-पिता को अपने वर्णनकर्ताओं के साथ कुछ भी करने की आवश्यकता नहीं है। जब बच्चा समाप्त हो जाता है, तो बच्चे द्वारा पढ़ने या लिखने के लिए साझा किए गए किसी भी वर्णित वर्णनकर्ता के अनुसार उनके फ़ाइल ऑफ़सेट अपडेट किए जाएंगे।

  2. माता-पिता और बच्चे दोनों अपने तरीके से जाते हैं। यहां, कांटा के बाद, माता-पिता उन वर्णनकर्ताओं को बंद कर देते हैं जिनकी आवश्यकता नहीं होती है, और बच्चा वही काम करता है। इस तरह, न तो दूसरे के खुले वर्णनकर्ताओं में हस्तक्षेप करता है। इस परिदृश्य अक्सर नेटवर्क सर्वर के साथ मामला जब कांटा() उत्पन्न होता है, सब मुझे समझ है कि बच्चे इस मामले में क्या माता पिता है, फ़ाइल वर्णनकर्ता की एक प्रति प्राप्त है। "

[3, और इसकी बात करता है। यदि किसी भी वर्णनकर्ता दायर करने के लिए माता-पिता और बच्चे हिस्सा है, यह केवल किया जा सकता है क्योंकि वर्णनकर्ता याद ही ऑफसेट परिवर्तन ऑफसेट। क्या मैं सही हूँ?]

खेद है कि मैं तरह अवधारणाओं के लिए नए की कर रहा हूँ ।

कोई मदद? धन्यवाद।

उत्तर

67

यह फ़ाइल वर्णनकर्ता, जो एक छोटे पूर्णांक है कि इस प्रक्रिया फ़ाइल की पहचान करने के लिए अपने पढ़ने और लिखने कॉल में उपयोग करता है, और फ़ाइल वर्णन, जो कर्नेल में एक संरचना है के बीच अंतर करना महत्वपूर्ण है। फ़ाइल ऑफ़सेट फ़ाइल विवरण का हिस्सा है। यह कर्नेल में रहता है।

#include <unistd.h> 
#include <fcntl.h> 
#include <sys/wait.h> 

int main(void) 
{ 
    int fd; 

    fd = open("output", O_CREAT|O_TRUNC|O_WRONLY, 0666); 

    if(!fork()) { 
     /* child */ 
     write(fd, "hello ", 6); 
     _exit(0); 
    } else { 
     /* parent */ 
     int status; 

     wait(&status); 
     write(fd, "world\n", 6); 
    } 
} 

(सभी त्रुटि जाँच हटा दिया गया है)

हम इस कार्यक्रम संकलन है, यह hello कहते हैं, और इस तरह इसे चलाने:

उदाहरण के लिए, के लिए इस कार्यक्रम का उपयोग करते हैं

./hello 

यहाँ क्या होता है:

कार्यक्रम खुला output फ़ाइल, इसे बनाकर अगर यह पहले से मौजूद नहीं है या शून्य आकार में इसे छोटा कर रहा है तो यह अस्तित्व में है। कर्नेल फ़ाइल विवरण बनाता है (लिनक्स कर्नेल में यह struct file है) और इसे कॉलिंग प्रक्रिया के लिए फ़ाइल डिस्क्रिप्टर से जोड़ता है (सबसे कम गैर-ऋणात्मक पूर्णांक पहले से ही उस प्रक्रिया की फ़ाइल डिस्क्रिप्टर तालिका में उपयोग में नहीं है)। फ़ाइल डिस्क्रिप्टर वापस कर दिया गया है और कार्यक्रम में fd को सौंपा गया है। तर्क के लिए मान लीजिए कि fd है 3.

कार्यक्रम एक कांटा() करता है। नई बाल प्रक्रिया को अपने माता-पिता की फ़ाइल डिस्क्रिप्टर तालिका की कॉपी करता है, लेकिन फ़ाइल विवरण की प्रतिलिपि नहीं बनाई जाती है। दोनों प्रक्रियाओं की फ़ाइल तालिकाओं में प्रविष्टि संख्या 3 उसी struct file पर इंगित करती है।

बाल प्रक्रिया लिखते समय मूल प्रक्रिया प्रतीक्षा करती है। बच्चे के लेखन में फ़ाइल में संग्रहीत होने के लिए "hello world\n" की पहली छमाही का कारण बनता है, और फ़ाइल को 6 से ऑफसेट करने की प्रगति होती है। फ़ाइल ऑफसेट struct file में है!

बच्चा निकलता है, माता-पिता का wait() खत्म होता है, और माता-पिता एफडी 3 का उपयोग करते हुए लिखते हैं, जो अभी भी उसी फ़ाइल विवरण से जुड़ा हुआ है जिसकी फ़ाइल ऑफसेट बच्चे के write() द्वारा अपडेट की गई थी। इसलिए संदेश का दूसरा भाग के बाद पहले भाग में संग्रहीत नहीं किया गया है, अगर इसे मूल रूप से शून्य का फ़ाइल ऑफसेट होता है, तो यह होगा अगर फ़ाइल विवरण साझा नहीं किया गया था तो यह होगा।

अंततः अभिभावक बाहर निकलता है, और कर्नेल देखता है कि struct file अब उपयोग में नहीं है और इसे मुक्त करता है।

+1

एलन, स्पष्टीकरण बहुत अच्छा है! समय लेने और एक नौसिखिया के लिए इस तरह के विस्तार में व्याख्या करने के लिए धन्यवाद। – user1559625

+1

@AlanCurry क्या होगा अगर मैं मूल कार्यक्रम में प्रतीक्षा() का उपयोग नहीं करता?क्या मूल विवरण बाहर निकलने के रूप में फ़ाइल विवरण मुक्त होगा? – Nmzzz

+0

सहायक! धन्यवाद! – Kross

3

पुस्तक के उसी खंड में, एक चित्र है जो एक फ़ाइल खोले जाने पर तीन टेबल दिखाती है।

उपयोगकर्ता दायर परीक्षक तालिका (प्रक्रिया तालिका प्रविष्टि का हिस्सा), फ़ाइलटेबल और इनोड तालिका (v-node तालिका)। अब एक दायरस्क्रिप्टर (जो फाइल डिस्क्रिप्टर टेबल के लिए एक सूचकांक है) प्रविष्टि बिंदु फ़ाइल तालिका प्रविष्टि को इंगित करता है, जो एक इनोड तालिका प्रविष्टि को इंगित करता है।
अब फ़ाइल ऑफसेट (जहां से पढ़ा/लिखना होता है वहां से स्थिति) फ़ाइल तालिका में है।

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

यह वर्णनकर्ता अब उसी तालिका तालिका प्रविष्टि को इंगित करते हुए, माता-पिता और बच्चे दोनों में उपलब्ध है, इसलिए ऑफ़सेट साझा करना। अब इस पृष्ठभूमि हमें अपने प्रश्न देखते हैं होने,

  1. इसका क्या मतलब है? अगर माता-पिता के std आउटपुट को 'file1' पर रीडायरेक्ट किया गया है, तो बच्चे के लिखने के बाद बच्चे को क्या अपडेट करना चाहिए? माता-पिता का मूल std आउटपुट ऑफसेट या रीडायरेक्ट आउटपुट (यानी फ़ाइल 1) ऑफ़सेट? बाद में नहीं हो सकता है, है ना?]

बच्चे को स्पष्ट रूप से कुछ भी अपडेट करने की आवश्यकता नहीं है। पुस्तक का लेखक
को आजमा रहा है, मान लीजिए कि, माता-पिता के मानक आउट डालने को फ़ाइल में रीडायरेक्ट किया जाता है और एक कांटा कॉल किया जाता है। उसके बाद अभिभावक wating है। तो वर्णनकर्ता अब डुप्लिकेट किया गया है, यह फ़ाइल ऑफसेट भी साझा किया जाता है। अब जब भी बच्चा मानक के लिए कुछ भी लिखता है, लिखित डेटा पुनर्निर्देशित फ़ाइल में सहेजा जाता है। ऑफसेट स्वचालित रूप से लिखने वाले कॉल द्वारा बढ़ाया जाता है।

अब कहें कि बच्चा निकलता है। तो माता-पिता प्रतीक्षा करने से बाहर आते हैं और मानक आउट पर कुछ लिखते हैं (जो पुनर्निर्देशित है)। अब जहां माता-पिता के लेखन कॉल का आउटपुट रखा जाएगा -> डेटा के बाद, जिसे बच्चे द्वारा लिखा गया था। क्यों -> चूंकि बच्चे के लिखे जाने के बाद ऑफसेट का वर्तमान मूल्य अब बदल गया है।

Parent () 
    { 
    open a file for writing, that is get the 
    descriptor(say fd); 
    close(1);//Closing stdout 
    dup(fd); //Now writing to stdout means writing to the file 
    close(fd) 
     //Create a child that is do a fork call. 
    ret = fork(); 
    if (0 == ret) 
    { 
     write(1, "Child", strlen("Child"); 
     exit .. 
    } 
     wait(); //Parent waits till child exit. 

     write(1, "Parent", strlen("Parent"); 
    exit .. 
} 

Pl। उपरोक्त छद्म कोड देखें, खोला गया फ़ाइल वाला अंतिम डेटा बाल अभिभावक होगा। तो आप देखते हैं कि बच्चे ने लिखा है जब फ़ाइल ऑफ़सेट बदल गया है और यह माता-पिता के लेखन कॉल के लिए उपलब्ध था, क्योंकि ऑफस्ट साझा किया गया था।

2. अद्यतन कैसे किया जाता है? बच्चे द्वारा स्पष्ट रूप से, ओएस द्वारा निस्संदेह, फाइल डिस्क्रिप्टर द्वारा स्वयं? कांटा के बाद, मैंने सोचा कि माता-पिता और बच्चे अपने तरीके से गए हैं और में फाइल डिस्क्रिप्टर की अपनी कॉपी है। तो बच्चे को मूल पक्ष में ऑफसेट कैसे अपडेट किया जाता है?]

Now I think the answer is clear-> by the system call that is by the OS. 

[3। जब कांटा() का आह्वान किया जाता है, तो मैं समझता हूं कि बच्चे को इस मामले में माता-पिता के पास फ़ाइल डिस्क्रिप्टर की एक प्रति प्राप्त होती है, और इसकी बात होती है। यदि कोई ऑफसेट फ़ाइल डिस्क्रिप्टर में बदलता है जो अभिभावक और बच्चे साझा करता है, तो यह केवल इसलिए हो सकता है क्योंकि वर्णनकर्ता स्वयं ऑफसेट को याद रखता है। क्या मैं सही हूँ?]

यह भी स्पष्ट होना चाहिए। उपयोगकर्ता फ़ाइल तालिका की प्रविष्टि फ़ाइल तालिका तालिका प्रविष्टि को इंगित करती है (जिसमें ऑफ़सेट होता है)।

दूसरे शब्दों में, सिस्टम कॉल ऑफसेट को डिस्क्रिप्टर से ला सकता है।

+0

"फ़ाइल तालिका प्रविष्टि में संदर्भ गणना (उस खुले डिस्क्रिप्टर के लिए) बढ़ी है"। क्या आप इसके लिए एक संदर्भ को इंगित कर सकते हैं? इसका मतलब है कांटा प्रतियां माता-पिता की स्मृति एक उथली प्रति नहीं है। – dashesy

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