2011-01-31 34 views
160

के बीच का अंतर मैं Google पर इन चारों के बीच अंतर ढूंढ रहा था और मुझे उम्मीद थी कि इस पर बड़ी मात्रा में जानकारी होगी, लेकिन वास्तव में वहां चार कॉल के बीच कोई ठोस तुलना नहीं थी।फोर्क(), vfork(), exec() और क्लोन()

मैंने इन सिस्टम कॉल के बीच मतभेदों को देखने के लिए एक तरह की बुनियादी संरचना को संकलित करने की कोशिश करने के बारे में सेट किया है और यहां मुझे जो मिला है। क्या यह सारी जानकारी सही है/क्या मुझे कुछ भी महत्वपूर्ण याद आ रही है?

Fork: कांटा कॉल मूल रूप से लगभग हर तरह से (नहीं सब कुछ खत्म हो गया नकल की जाती है, उदाहरण के लिए, कुछ कार्यान्वयन में संसाधन सीमा लेकिन यह विचार अधिक से अधिक निकट प्रतिलिपि बनाने के लिए है में वर्तमान प्रक्रिया का डुप्लिकेट, समान बनाता है)।

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

Vfork: vfork और कांटा के बीच मूल अंतर यह है कि जब vfork() के साथ एक नई प्रक्रिया बनाई जाती है, तो मूल प्रक्रिया अस्थायी रूप से निलंबित कर दी जाती है, और बच्चे की प्रक्रिया माता-पिता की पता स्थान उधार ले सकती है। यह अजीब स्थिति तब तक जारी है जब तक कि बच्चे की प्रक्रिया या तो बाहर निकलती है, या कॉल निष्पादित(), जिस बिंदु पर माता-पिता प्रक्रिया जारी है।

इसका मतलब है कि एक vfork() की बाल प्रक्रिया को माता-पिता प्रक्रिया के अप्रत्याशित रूप से संशोधित चर से बचने के लिए सावधान रहना चाहिए। विशेष रूप से, बच्चे की प्रक्रिया vfork() कॉल वाले फ़ंक्शन से वापस नहीं आनी चाहिए, और इसे बाहर निकलने की आवश्यकता नहीं है() (अगर इसे बाहर निकलने की आवश्यकता है, तो इसे _exit() का उपयोग करना चाहिए; असल में, यह बच्चे के लिए भी सच है एक सामान्य कांटा())।

Exec : निष्पादन कॉल मूल रूप से पूरी प्रक्रिया को एक नए कार्यक्रम के साथ बदलने का एक तरीका है। यह प्रोग्राम को वर्तमान प्रक्रिया स्थान में लोड करता है और इसे प्रवेश बिंदु से चलाता है। exec() फ़ंक्शन द्वारा इंगित निष्पादन योग्य के साथ वर्तमान प्रक्रिया को प्रतिस्थापित करता है। नियंत्रण तब तक मूल प्रोग्राम पर वापस नहीं आ जाता जब तक कोई निष्पादन() त्रुटि न हो।

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

जब क्लोन के साथ बाल प्रक्रिया बनाई जाती है, तो यह फ़ंक्शन एप्लिकेशन fn (arg) निष्पादित करता है। (यह कांटा से अलग है, जहां मूल फोर्क कॉल के बिंदु से बच्चे में निष्पादन जारी रहता है।) एफएन तर्क एक समारोह के लिए एक सूचक है जिसे बाल निष्पादन की शुरुआत में बाल प्रक्रिया द्वारा बुलाया जाता है। तर्क तर्क एफएन समारोह में पारित किया जाता है।

जब एफएन (तर्क) फ़ंक्शन एप्लिकेशन लौटाता है, तो बच्चे की प्रक्रिया समाप्त हो जाती है। एफएन द्वारा लौटाया गया पूर्णांक बाल प्रक्रिया के लिए निकास कोड है। बच्चे की प्रक्रिया बाहर निकलने (2) या घातक सिग्नल प्राप्त करने के बाद स्पष्ट रूप से समाप्त हो सकती है।

सूचना मिल प्रपत्र:

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

+2

vfork को बाहर निकलने के लिए क्यों कॉल नहीं करना चाहिए()? या वापस नहीं? बाहर निकलें नहीं() बस _exit() का उपयोग करें? मैं भी समझने की कोशिश कर रहा हूं :) – LazerSharks

+2

@Gnuey: क्योंकि यह संभावित रूप से है (यदि इसे 'फोर्क()' से अलग किया गया है, जो कि लिनक्स में है, और शायद सभी बीएसडी) अपने माता-पिता की पता स्थान उधार लेते हैं। 'Execve()' या '_exit()' को कॉल करने के अलावा, यह कुछ भी करता है, माता-पिता को गड़बड़ करने की एक बड़ी संभावना है। विशेष रूप से, 'बाहर निकलें()' कॉल 'atexit()' हैंडलर और अन्य "फ़ाइनलाइज़र", उदाहरण: यह stdio धाराओं को फ़्लश करता है। एक 'vfork() 'बच्चे से लौटने से संभावित रूप से (पहले की तरह ही चेतावनी) माता-पिता के ढेर को गड़बड़ कर देगी। – ninjalj

+0

मैं सोच रहा था कि पैरेंट प्रक्रिया के धागे के साथ क्या होता है; क्या वे सभी क्लोन किए गए हैं या केवल थ्रेड जो 'कांटा' syscall कहते हैं? –

उत्तर

121
  • vfork() एक अप्रचलित अनुकूलन है। अच्छी मेमोरी प्रबंधन से पहले, fork() ने माता-पिता की स्मृति की पूरी प्रति बना दी, इसलिए यह बहुत महंगा था। चूंकि कई मामलों में fork()exec() द्वारा पीछा किया गया था, जो वर्तमान मेमोरी मानचित्र को छोड़ देता है और एक नया बनाता है, यह एक आवश्यक व्यय था। आजकल, fork() स्मृति की प्रतिलिपि नहीं करता है; इसे बस "लिखने पर प्रतिलिपि" के रूप में सेट किया गया है, इसलिए fork() + exec()vfork() + exec() जितना ही कुशल है।

  • clone()fork() द्वारा उपयोग किया जाने वाला सिस्कल है। कुछ मानकों के साथ, यह एक नई प्रक्रिया बनाता है, दूसरों के साथ, यह एक धागा बनाता है। उनके बीच का अंतर सिर्फ डेटा संरचनाओं (मेमोरी स्पेस, प्रोसेसर स्टेट, स्टैक, पीआईडी, ओपन फाइल इत्यादि) साझा या नहीं हैं।

+8

संबंधित: [क्या यह सच है कि कांटा() आंतरिक रूप से क्लोन() कॉल करता है?] (Http://stackoverflow.com/q/18904292/1937994) – gronostaj

+2

यह भी संबंधित है: http://unix.stackexchange.com/questions/87551/कौन-फ़ाइल-इन-कर्नेल-निर्दिष्ट-फोर्क-वर्फ-टू-यूज-सीएस-क्लोन-सिस्टम-कॉल –

+17

'vfork' अस्थायी रूप से अधिक स्मृति को कम करने की आवश्यकता से बचाता है, इसलिए कोई भी' exec' निष्पादित कर सकता है, और यह अभी भी 'फोर्क' की तुलना में अधिक कुशल है, भले ही लगभग एक डिग्री से अधिक न हो। इस प्रकार, कोई भी स्मृति को कम करने से बच सकता है, इसलिए एक हंकिंग बड़ा कार्यक्रम एक बच्चे की प्रक्रिया को जन्म दे सकता है। तो, न केवल एक प्रदर्शन-बढ़ावा, बल्कि यह संभव है कि यह संभव हो। – Deduplicator

65
  • execve() एक निष्पादन योग्य फ़ाइल से लोड एक दूसरे के साथ मौजूदा निष्पादन योग्य छवि बदल देता है।
  • fork() एक बाल प्रक्रिया बनाता है।
  • vfork()fork() का ऐतिहासिक अनुकूलित संस्करण है, जिसका उपयोग execve() को fork() के बाद सीधे कहा जाता है। यह गैर-एमएमयू सिस्टम में अच्छी तरह से काम करने के लिए निकला (जहां fork() कुशल तरीके से काम नहीं कर सकता) और जब fork() आईएनजी प्रक्रियाओं को एक छोटे से स्मृति प्रोग्राम के साथ एक छोटे से स्मृति पदचिह्न के साथ प्रक्रिया करता है (जावा का Runtime.exec() सोचें)। vfork() के बाद के दो और आधुनिक उपयोगों को प्रतिस्थापित करने के लिए POSIX ने posix_spawn() को मानकीकृत किया है।
  • posix_spawn()fork()/execve() के बराबर है, और इसमें कुछ एफडी जुगलिंग भी शामिल है। यह fork()/execve() को मुख्य रूप से गैर-एमएमयू प्लेटफ़ॉर्म के लिए प्रतिस्थापित करना है।
  • pthread_create() एक नया धागा बनाता है।
  • clone() एक लिनक्स-विशिष्ट कॉल है, जिसका उपयोग fork() से pthread_create() से कुछ भी लागू करने के लिए किया जा सकता है। यह बहुत नियंत्रण देता है। rfork() पर प्रेरित
  • rfork() एक योजना -9 विशिष्ट कॉल है। यह एक सामान्य कॉल माना जाता है, जो पूर्ण प्रक्रियाओं और धागे के बीच साझा करने की कई डिग्री देता है।
+1

वास्तव में पूछे जाने वाले अधिक जानकारी जोड़ने के लिए धन्यवाद, इससे मुझे अपना समय बचाने में मदद मिली – Neeraj

+0

प्लान 9 ऐसी चिढ़ा है। –

-2

कांटा में(), या तो बच्चे या माता पिता प्रक्रिया cpu चयन .. पर लेकिन vfork() में आधारित निष्पादित करेंगे, निश्चित रूप से बच्चे को पहले निष्पादित करेंगे। बच्चे को समाप्त करने के बाद, माता-पिता निष्पादित होंगे।

+3

गलत। 'vfork()' को केवल 'कांटा() 'के रूप में कार्यान्वित किया जा सकता है। Anyfork() के बाद – ninjalj

+0

, यह परिभाषित नहीं किया गया है कि कौन पहले माता-पिता/बच्चे को चलाता है। – AjayKumarBasuthkar

+4

@ राज: यदि आपके पास सोचने के बाद लगता है कि सीरियल ऑर्डर की एक अंतर्निहित धारणा है तो आपके पास कुछ वैचारिक गलतफहमी हैं। फोर्किंग एक * नई * प्रक्रिया बनाता है और फिर दोनों प्रक्रियाओं पर नियंत्रण देता है (प्रत्येक एक अलग 'पिड' लौटाता है) - ऑपरेटिंग सिस्टम समान प्रक्रिया में चलाने के लिए नई प्रक्रिया को शेड्यूल कर सकता है यदि ऐसी चीज समझ में आती है (जैसे एकाधिक प्रोसेसर)। अगर किसी कारण से आपको किसी विशेष धारावाहिक क्रम में निष्पादित करने के लिए इन प्रक्रियाओं की आवश्यकता होती है, तो आपको अतिरिक्त सिंक्रनाइज़ेशन की आवश्यकता होती है जो फोर्किंग प्रदान नहीं करता है; स्पष्ट रूप से, आप शायद पहले ही एक कांटा भी नहीं चाहते हैं। –

3

फोर्क(), vfork() और क्लोन() सभी वास्तविक कार्य करने के लिए do_fork() को कॉल करते हैं, लेकिन विभिन्न मानकों के साथ।

asmlinkage int sys_fork(struct pt_regs regs) 
{ 
    return do_fork(SIGCHLD, regs.esp, &regs, 0); 
} 

asmlinkage int sys_clone(struct pt_regs regs) 
{ 
    unsigned long clone_flags; 
    unsigned long newsp; 

    clone_flags = regs.ebx; 
    newsp = regs.ecx; 
    if (!newsp) 
     newsp = regs.esp; 
    return do_fork(clone_flags, newsp, &regs, 0); 
} 
asmlinkage int sys_vfork(struct pt_regs regs) 
{ 
    return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs.esp, &regs, 0); 
} 
#define CLONE_VFORK 0x00004000 /* set if the parent wants the child to wake it up on mm_release */ 
#define CLONE_VM 0x00000100 /* set if VM shared between processes */ 

SIGCHLD means the child should send this signal to its father when exit. 

कांटा, बच्चे और पिता के लिए स्वतंत्र वीएम पेज टेबल है, लेकिन क्षमता के बाद से, कांटा वास्तव में किसी भी पृष्ठों कॉपी नहीं करेंगे, यह सिर्फ बच्चे की प्रक्रिया के लिए केवल पढ़ने के लिए करने के लिए सभी लिखने योग्य पृष्ठों की स्थापना की। तो जब बच्चे की प्रक्रिया उस पृष्ठ पर कुछ लिखना चाहती है, तो एक पृष्ठ अपवाद होता है और कर्नेल पुराने पृष्ठ से लिखित अनुमति के साथ क्लोन किए गए एक नए पृष्ठ को आवंटित करेगा। इसे "लिखने पर प्रतिलिपि" कहा जाता है।

vfork के लिए, वर्चुअल मेमोरी बिल्कुल बच्चे और पिता द्वारा है --- सिर्फ इसलिए, पिता और बच्चे एक दूसरे से प्रभावित होने के बाद एक साथ जाग नहीं सकते हैं। तो पिता "do_fork()" के अंत में सोएंगे और जागते हैं जब बच्चे से बाहर निकलें() या execve() तब से यह नई पेज तालिका का मालिक होगा। यहां कोड है (do_fork() में) कि पिता सोते हैं।

if ((clone_flags & CLONE_VFORK) && (retval > 0)) 
down(&sem); 
return retval; 

यहाँ (() mm_release में() बाहर निकलने के द्वारा कहा जाता है और execve()) कोड है जो पिता जाग है।

up(tsk->p_opptr->vfork_sem); 

sys_clone() के लिए, यह अधिक लचीला है क्योंकि आप इसे क्लोन_फ्लैग इनपुट कर सकते हैं। तो pthread_create() कई clone_flags के साथ इस सिस्टम कॉल पर कॉल करें:

पूर्णांक clone_flags = (CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGNAL | CLONE_SETTLS | CLONE_PARENT_SETTID | CLONE_CHILD_CLEARTID | CLONE_SYSVSEM);

सारांश: कांटा(), vfork() और क्लोन() पिता प्रक्रिया के साथ संसाधन साझा करने के विभिन्न माउंट के साथ बाल प्रक्रियाएं बनाएंगे। हम यह भी कह सकते हैं कि vfork() और क्लोन() थ्रेड बना सकते हैं (असल में वे प्रक्रियाएं हैं क्योंकि उनके पास स्वतंत्र कार्य_स्ट्रक्चर है) क्योंकि वे वीएम पेज टेबल को पिता प्रक्रिया के साथ साझा करते हैं।

20
  1. fork() - एक नई बाल प्रक्रिया बनाता है, जो मूल प्रक्रिया की पूरी प्रति है। बाल और अभिभावक प्रक्रियाएं विभिन्न आभासी पता रिक्त स्थान का उपयोग करती हैं, जो प्रारंभ में उसी स्मृति पृष्ठों द्वारा पॉप्युलेट की जाती हैं। फिर, चूंकि दोनों प्रक्रियाओं को निष्पादित किया जाता है, वर्चुअल एड्रेस रिक्त स्थान अधिक से अधिक भिन्न होने लगते हैं, क्योंकि ऑपरेटिंग सिस्टम इन दो प्रक्रियाओं में से किसी एक द्वारा लिखे गए मेमोरी पृष्ठों की आलसी प्रतिलिपि करता है और संशोधित पृष्ठों की एक स्वतंत्र प्रतियां निर्दिष्ट करता है प्रत्येक प्रक्रिया के लिए स्मृति। इस तकनीक को कॉपी-ऑन-लिखित (गाय) कहा जाता है।
  2. vfork() - एक नई बाल प्रक्रिया बनाता है, जो मूल प्रक्रिया की "त्वरित" प्रति है। सिस्टम कॉल fork() के विपरीत, बच्चे और अभिभावक प्रक्रियाएं समान वर्चुअल एड्रेस स्पेस साझा करती हैं। ध्यान दें! उसी वर्चुअल एड्रेस स्पेस का उपयोग करते हुए, क्लासिक fork() के मामले में माता-पिता और बच्चे दोनों एक ही स्टैक, स्टैक पॉइंटर और निर्देश पॉइंटर का उपयोग करते हैं! माता-पिता और बच्चे के बीच अवांछित हस्तक्षेप को रोकने के लिए, जो एक ही स्टैक का उपयोग करते हैं, पैरेंट प्रक्रिया का निष्पादन तब तक जमे हुए है जब तक कि बच्चे exec() (एक नया वर्चुअल एड्रेस स्पेस और एक अलग स्टैक में संक्रमण) या _exit() को कॉल करेगा प्रक्रिया निष्पादन)। vfork() "फोर्क-एंड-निष्पादन" मॉडल के लिए fork() का अनुकूलन है। इसे fork() से 4-5 गुना तेजी से किया जा सकता है, क्योंकि fork() (यहां तक ​​कि गाय में रखा गया है) के विपरीत, vfork() सिस्टम कॉल के कार्यान्वयन में एक नई पता स्थान (आवंटन और नई स्थापना की स्थापना शामिल नहीं है) पेज निर्देशिका)।
  3. clone() - एक नई बाल प्रक्रिया बनाता है। इस सिस्टम कॉल के विभिन्न पैरामीटर, निर्दिष्ट करें कि मूल प्रक्रिया के कौन से हिस्सों को बाल प्रक्रिया में कॉपी किया जाना चाहिए और उनके बीच कौन से हिस्से साझा किए जाएंगे। नतीजतन, इस सिस्टम कॉल का उपयोग सभी प्रकार की निष्पादन इकाइयों को बनाने के लिए किया जा सकता है, जो धागे से शुरू होते हैं और पूरी तरह से स्वतंत्र प्रक्रियाओं से परिष्करण करते हैं।वास्तव में, clone() सिस्टम कॉल वह आधार है जिसका उपयोग pthread_create() के कार्यान्वयन और fork() सिस्टम कॉल के सभी परिवार के कार्यान्वयन के लिए किया जाता है।
  4. exec() - प्रक्रिया निष्पादन योग्य बाइनरी की प्रक्रिया, लोड और पार्स की सभी मेमोरी रीसेट करता है, नया स्टैक सेट करता है और लोड निष्पादन योग्य के प्रवेश बिंदु पर नियंत्रण पास करता है। यह सिस्टम कॉल कॉलर को कभी भी नियंत्रण नहीं देता है और पहले से ही मौजूदा प्रक्रिया में एक नया प्रोग्राम लोड करने के लिए कार्य करता है। इस प्रणाली को fork() सिस्टम कॉल के साथ कॉल करने के लिए एक शास्त्रीय यूनिक्स प्रक्रिया प्रबंधन मॉडल "फोर्क-एंड-निष्पादन" कहा जाता है।
+0

स्वीकार्य एक से बेहतर जवाब है। – yabhishek

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