2014-10-23 7 views
6

यह, एक तकनीकी सवाल की तरह है हो सकता है आप मेरी मदद कर सकते हैं यदि आप सी और यूनिक्स के बारे में पता है (या शायद यह एक बहुत नौसिखिया सवाल है!)कांटा के बाद संकेत() के बारे में

एक सवाल आज आया था, जबकि हमारे ऑपरेटिव सिस्टम कोर्स में कुछ कोड का आकलन करना। हम सीख रहे हैं कि यूनिक्स में एक प्रक्रिया को "फोर्क" करने का क्या अर्थ है, हम पहले ही जानते हैं कि यह वर्तमान प्रक्रिया की एक प्रतिलिपि बनाता है और उनके पास अलग-अलग डेटा अनुभाग हैं।

लेकिन फिर मैंने सोचा कि शायद, अगर कोई एक चर और एक पॉइंटर बनाता है जो फोर्क() करने से पहले इंगित करता है, क्योंकि पॉइंटर चर के स्मृति पते को संग्रहीत करता है, तो कोई उस चर के मान को संशोधित करने का प्रयास कर सकता है उस सूचक का उपयोग करके बच्चे की प्रक्रिया।

जनक:

#include <stdio.h> 
#include <sys/types.h> 
#include <stdlib.h> 

int main(){ 
    int value = 0; 
    int * pointer = &value; 
    int status; 

    pid_t pid; 

    printf("Parent: Initial value is %d\n",value); 

    pid = fork(); 

    switch(pid){ 
    case -1: //Error (maybe?) 
     printf("Fork error, WTF?\n"); 
     exit(-1); 

    case 0: //Child process 
     printf("\tChild: I'll try to change the value\n\tChild: The pointer value is %p\n",pointer); 
     (*pointer) = 1; 
     printf("\tChild: I've set the value to %d\n",(*pointer)); 

     exit(EXIT_SUCCESS); 
     break; 
    } 

    while(pid != wait(&status)); //Wait for the child process 

    printf("Parent: the pointer value is %p\nParent: The value is %d\n",pointer,value); 

    return 0; 
} 

आप इसे चलाते हैं, तो आप इस तरह कुछ मिल जाएगा:

हम कक्षा में एक कोड इस के समान करने की कोशिश की प्रारंभिक मान 0

है बच्चा: मैं मूल्य

बच्चे को बदलने की कोशिश करूंगा: सूचक मूल्य 0x7fff733b0c6c

बाल: मैं 1

जनक के लिए मूल्य निर्धारित किया है: मूल्य 0

यह स्पष्ट है कि बच्चे की प्रक्रिया को प्रभावित नहीं किया है: सूचक मूल्य 0x7fff733b0c6c

जनक है सभी मूल प्रक्रिया पर। स्पष्ट रूप से, मुझे कुछ "सेगमेंटेशन गलती" त्रुटि की उम्मीद नहीं थी, क्योंकि स्वीकृत स्मृति पता तक पहुंचने की वजह से। लेकिन वास्तव में क्या हुआ?

याद रखें, मैं प्रक्रियाओं को संवाद करने का कोई तरीका नहीं ढूंढ रहा हूं, यह बात नहीं है। मैं क्या जानना चाहता हूं कि कोड क्या करता है। बाल प्रक्रिया के अंदर, परिवर्तन दिखाई दे रहा है, इसलिए यह कुछ छिपा हुआ है।

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

अपना समय पढ़ने के लिए धन्यवाद!

+0

आप 'printf (" अभिभावक: सूचक मूल्य% p \ n मान डाल सकते हैं \ n मूल्य% d \ n ", सूचक, मान);' 'स्विच()' – Haris

+2

http:/के डिफ़ॉल्ट मामले में /en.wikipedia.org/wiki/Virtual_memory – Mat

+0

"* स्पष्ट रूप से, मुझे कुछ" सेगमेंटेशन गलती "त्रुटि की उम्मीद नहीं थी, क्योंकि एक अनुमत स्मृति पता तक पहुंचने के कारण। *" इसका कोई मतलब नहीं है। इसके बारे में सोचो। बच्चा निष्पादित कोड पूरी तरह कानूनी है। एकमात्र सवाल यह है - क्या यह माता-पिता को प्रभावित करता है या नहीं? प्रत्येक प्रक्रिया में –

उत्तर

11

यहां कुंजी वर्चुअल एड्रेस स्पेस की अवधारणा है।

आधुनिक प्रोसेसर (80386 के बाद कुछ भी नया कहें) में एक मेमोरी मैनेजमेंट यूनिट है जो प्रति प्रक्रिया वर्चुअल एड्रेस स्पेस से कर्नेल के नियंत्रण में भौतिक मेमोरी पेजों पर मैप करती है।

जब कर्नेल एक प्रक्रिया सेट करता है तो यह उस प्रक्रिया के लिए पृष्ठ तालिका प्रविष्टियों का एक सेट बनाता है जो भौतिक स्मृति पृष्ठों को वर्चुअल एड्रेस स्पेस मैपिंग में परिभाषित करता है, और यह इस वर्चुअल एड्रेस स्पेस में प्रोग्राम निष्पादित करता है।

संकल्पनात्मक रूप से जब आप कांटा, कर्नेल मौजूदा प्रक्रिया पृष्ठों को भौतिक पृष्ठों के एक नए सेट पर प्रतिलिपि बनाता है और नई प्रक्रियाओं को पृष्ठ सारणी सेट करता है ताकि जहां तक ​​नई प्रक्रिया का संबंध है, वही वर्चुअल में चल रहा है मेमोरी लेआउट मूल के रूप में था, जबकि वास्तव में पूरी तरह से अलग शारीरिक स्मृति को संबोधित करते हुए।

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

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

सम्मान, दान।

3

बच्चे ने एक सूचक को संशोधित किया जो अपने पता स्थान में पूरी तरह से कानूनी है क्योंकि यह अपने माता-पिता की एक प्रति है। माता-पिता पर कोई प्रभाव नहीं पड़ा क्योंकि स्मृति को तार्किक रूप से साझा नहीं किया गया है। कांटा के बाद प्रत्येक प्रक्रिया को अलग तरीके से जाना पड़ता है।

यूनिक्स में साझा स्मृति बनाने के कई तरीके हैं (जहां एक प्रक्रिया मेमोरी को संशोधित कर सकती है और उस प्रक्रिया को किसी अन्य प्रक्रिया द्वारा देखा जा सकता है), लेकिन fork उनमें से एक नहीं है। और यह एक अच्छी बात है क्योंकि अन्यथा, माता-पिता और बच्चे के बीच सिंक्रनाइज़ेशन लगभग असंभव होगा।

+0

लेकिन यह कानूनी क्यों है? क्या वह स्मृति पता माता-पिता के स्वामित्व में नहीं है? मान एक ही है – javierbg

+1

बच्चा माता-पिता के बारे में नहीं जानता या परवाह नहीं करता है। हां, माता-पिता का वह स्मृति पता है (इसकी पता स्थान में)। बच्चे का उस स्मृति पते का भी मालिक है (इसके पता स्थान में)। माता-पिता और बच्चे प्रतियों के रूप में शुरू होते हैं लेकिन फिर अपने अलग-अलग तरीकों से जा सकते हैं। मेमोरी रिक्त स्थान को कांटा के बाद अलग करने की अनुमति है, लेकिन वे इसके समान हैं। –

+0

तो, मुझे लगता है कि पॉइंटर्स पूर्ण स्मृति एड्रेस को भौतिक स्मृति में संग्रहीत नहीं करते हैं। क्या वो सही है? – javierbg

4

तार्किक रूप से, fork() एड प्रक्रिया को माता-पिता की प्रक्रिया की पूरी स्थिति को कम या कम की अपनी स्वतंत्र, स्वतंत्र प्रति प्राप्त होती है। यह काम नहीं कर सका अगर बच्चे के पॉइंटर्स माता-पिता से संबंधित स्मृति को संदर्भित करते हैं।

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

+0

मुझे इस समय वर्चुअल मेमोरी के बारे में बहुत कुछ पता नहीं है, इसलिए मुझे यह नहीं पता था। धन्यवाद! – javierbg

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