2010-11-17 14 views
70

बताएं exec() फ़ंक्शन और उसके परिवार क्या हैं? यह फ़ंक्शन क्यों उपयोग किया जाता है और यह कैसे काम करता है?कृपया exec() फ़ंक्शन और उसके परिवार को

कृपया कोई भी इन कार्यों को समझाएं।

+1

'आदमी 3 exec' मदद नहीं करता है:

अधिक जानकारी के लिए exec(3) man page पढ़ा है? – khachik

+2

स्टीवंस को दोबारा पढ़ने की कोशिश करें, और यह स्पष्ट करें कि आप क्या समझ में नहीं आ रहे हैं। – vlabrecque

उत्तर

3

exec(3,3p) फ़ंक्शन वर्तमान प्रक्रिया को दूसरे के साथ प्रतिस्थापित करें। यही है, वर्तमान प्रक्रिया रोकती है, और इसके बजाय दूसरा प्रोग्राम मूल संसाधनों के कुछ संसाधनों को लेता है।

+5

काफी नहीं। यह एक नई प्रक्रिया छवि के साथ वर्तमान प्रक्रिया * छवि * को बदल देता है। प्रक्रिया एक ही प्रक्रिया, एक ही वातावरण, और एक ही फाइल डिस्क्रिप्टर तालिका के साथ एक ही प्रक्रिया है। क्या बदल गया है पूरी वर्चुअल मेमोरी और सीपीयू राज्य है। – JeremyP

+0

@ जेरेमीपी "एक ही फाइल डिस्क्रिप्टर" यहां महत्वपूर्ण था, यह बताता है कि गोले में पुनर्निर्देशन कैसे काम करता है! अगर मैं सबकुछ ओवरराइट करता हूं तो मैं इस बात से परेशान था कि पुनर्निर्देशन कैसे काम कर सकता है! धन्यवाद – FUD

12

exec फ़ंक्शन का परिवार आपकी प्रक्रिया को एक पुराने प्रोग्राम को निष्पादित करता है, जो पुराने कार्यक्रम को बदल रहा था। अर्थात, यदि आप फोन

execl("/bin/ls", "ls", NULL); 

तो ls कार्यक्रम प्रक्रिया आईडी, वर्तमान कार्यशील निर्देशिका और उपयोगकर्ता/समूह (अधिकारों का उपयोग) प्रक्रिया है कि execl कहा जाता है के साथ निष्पादित किया जाता है। इसके बाद, मूल कार्यक्रम अब और नहीं चल रहा है।

एक नई प्रक्रिया शुरू करने के लिए, fork सिस्टम कॉल का उपयोग किया जाता है। मूल को बदले बिना प्रोग्राम निष्पादित करने के लिए, आपको fork, फिर exec की आवश्यकता है।

+0

धन्यवाद कि वास्तव में मददगार था। मैं वर्तमान में एक परियोजना कर रहा हूं जिसमें हमें exec() का उपयोग करने की आवश्यकता है और आपके विवरण ने मेरी समझ को मजबूत किया है। – TwilightSparkleTheGeek

4

निष्पादन कार्य और उसके परिवार क्या है।

exec समारोह परिवार एक फ़ाइल निष्पादित करने के लिए उपयोग किए गए सभी काम करता है, है इस तरह के execl, execlp, execle, execv, और execvp रूप .वे execve के लिए सभी फ़्रंटएंड्स रहे हैं और यह बुला के विभिन्न तरीकों प्रदान करते हैं।

क्यों इस्तेमाल किया

Exec कार्यों उपयोग किया जाता है जब आप (प्रक्षेपण) निष्पादित करने के लिए एक फ़ाइल (प्रोग्राम) चाहते हैं तो इस कार्य है।

और यह कैसे काम करता है।

वे आपके द्वारा लॉन्च किए गए वर्तमान प्रक्रिया छवि को ओवरराइट करके काम करते हैं। वे लॉन्च की गई नई प्रक्रिया के साथ वर्तमान में चल रही प्रक्रिया (जिसे निष्पादन आदेश कहा जाता है) को प्रतिस्थापित (समाप्त करके) प्रतिस्थापित करता है।

अधिक जानकारी के लिए: see this link

194

सरलीकृत रूप से, यूनिक्स में, आपके पास प्रक्रियाओं और कार्यक्रमों की अवधारणा है। एक प्रक्रिया कुछ ऐसा है जिसमें एक प्रोग्राम निष्पादित होता है।

यूनिक्स "निष्पादन मॉडल" के पीछे सरल विचार यह है कि आप दो ऑपरेशन कर सकते हैं।

पहला fork() है, जो एक नई नई प्रक्रिया बनाता है जिसमें वर्तमान स्थिति का डुप्लिकेट होता है, जिसमें इसके राज्य भी शामिल हैं। प्रक्रियाओं के बीच कुछ अंतर हैं जो उन्हें यह पता लगाने की अनुमति देते हैं कि माता-पिता कौन सा है और कौन सा बच्चा है।

दूसरा exec() है, जो वर्तमान प्रक्रिया में एक नए कार्यक्रम के साथ कार्यक्रम को प्रतिस्थापित करता है।

उन दो सरल संचालनों से, संपूर्ण यूनिक्स निष्पादन मॉडल का निर्माण किया जा सकता है।


ऊपर करने के लिए कुछ और अधिक विस्तार जोड़ने के लिए:

fork() और exec() के उपयोग में यह नई प्रक्रियाओं शुरू करने के लिए एक बहुत ही सरल तरीका प्रदान करता है कि यूनिक्स की भावना एक मिसाल है।

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

नई प्रक्रिया (बच्चे को बुलाया जाता है) एक अलग प्रक्रिया आईडी (पीआईडी) प्राप्त करता है और पुरानी प्रक्रिया का पीआईडी ​​होता है (माता-पिता) इसके मूल पीआईडी ​​(पीपीआईडी) के रूप में।

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

exec() कॉल एक नए कार्यक्रम के साथ प्रक्रिया की पूरी वर्तमान सामग्री को प्रतिस्थापित करता है। यह प्रोग्राम को वर्तमान प्रक्रिया स्थान में लोड करता है और इसे प्रवेश बिंदु से चलाता है।

तो, fork() और exec() अक्सर वर्तमान प्रक्रिया के बच्चे के रूप में एक नया प्रोग्राम चलाने के लिए अनुक्रम में उपयोग किया जाता है। शेल आमतौर पर ऐसा करते हैं जब आप find - शैल कांटे जैसे प्रोग्राम चलाने की कोशिश करते हैं, तो बच्चा find प्रोग्राम को मेमोरी में लोड करता है, सभी कमांड लाइन तर्क, मानक I/O और आगे की स्थापना करता है।

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

इसी तरह, प्रोग्राम जो जानते हैं कि वे समाप्त हो गए हैं और बस एक और प्रोग्राम चलाने के लिए चाहते हैं, fork(), exec() और फिर wait()/waitpid() बच्चे के लिए आवश्यक नहीं है। वे सिर्फ exec() के साथ सीधे अपने वर्तमान प्रक्रिया स्थान में बच्चे को लोड कर सकते हैं।

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

तो exec है (और यह क्या ज्यादातर होता है) के बाद fork कहा जाता है, कि इस प्रक्रिया अंतरिक्ष के लिए एक लिखने का कारण बनता है और यह उसके बाद बच्चे की प्रक्रिया के लिए नकल की जाती है।

लिनक्स में vfork() भी है, और भी अधिक अनुकूलन है, जो दो प्रक्रियाओं के बीच लगभग सब कुछ साझा करता है। इसके कारण, बच्चे द्वारा किए जा सकने वाले कुछ प्रतिबंध हैं, और जब तक बच्चा exec() या _exit() पर कॉल करता है तब तक माता-पिता रोकते हैं।

माता-पिता को रोकना होगा (और बच्चे को वर्तमान फ़ंक्शन से वापस जाने की अनुमति नहीं है) क्योंकि दोनों प्रक्रियाएं एक ही स्टैक साझा करती हैं। fork() के क्लासिक उपयोग केस के लिए यह थोड़ा अधिक कुशल है, तुरंत exec() द्वारा पीछा किया गया।

नोट exec कॉल (execl, execle, execve और इसी तरह) लेकिन संदर्भ में exec के एक पूरे परिवार है कि वहाँ यहाँ उनमें से किसी को मतलब है।

निम्न आरेख दिखाता है ठेठ fork/exec आपरेशन जहां bash खोल ls कमांड के साथ एक निर्देशिका सूची प्रयोग किया जाता है: अक्सर fork साथ संयोजन के रूप में प्रयोग किया जाता है

+--------+ 
| pid=7 | 
| ppid=4 | 
| bash | 
+--------+ 
    | 
    | calls fork 
    V 
+--------+    +--------+ 
| pid=7 | forks | pid=22 | 
| ppid=4 | ----------> | ppid=7 | 
| bash |    | bash | 
+--------+    +--------+ 
    |      | 
    | waits for pid 22  | calls exec to run ls 
    |      V 
    |     +--------+ 
    |     | pid=22 | 
    |     | ppid=7 | 
    |     | ls  | 
    V     +--------+ 
+--------+     | 
| pid=7 |     | exits 
| ppid=4 | <---------------+ 
| bash | 
+--------+ 
    | 
    | continues 
    V 
+6

इस तरह के विस्तृत स्पष्टीकरण के लिए धन्यवाद :) – Faizan

+1

खोज कार्यक्रम के साथ खोल संदर्भ के लिए धन्यवाद। वास्तव में मुझे समझने की जरूरत है। – User

+0

वर्तमान प्रक्रिया के आईओ को पुनर्निर्देशित करने के लिए उपयोग की जाने वाली उपयोगिता 'exec' क्यों है? तर्क के बिना निष्पादन चलाने वाले "शून्य" मामले को कैसे इस सम्मेलन के लिए उपयोग किया जाता है? – Ray

5

exec, जो मैंने देखा है कि आप यह भी पूछा के बारे में, इसलिए मैं इसे ध्यान में रखकर इस पर चर्चा करूंगा।

exec वर्तमान प्रक्रिया को दूसरे प्रोग्राम में बदल देता है। यदि आपने कभी डॉक्टर कौन देखा है, तो यह तब होता है जब वह पुनर्जन्म देता है - उसका पुराना शरीर एक नए शरीर के साथ बदल दिया जाता है।

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

कारण यह है कि इस इस तरह से किया जाता है कि अलग इस तरह दो चरणों मेंएकनईकार्यक्रम चलाकर आप दो कदम के बीच कुछ बातें कर सकते हैं। ऐसा करने के लिए सबसे आम बात यह सुनिश्चित करना है कि नए प्रोग्राम में कुछ फाइल डिस्क्रिप्टर के रूप में कुछ फाइलें खोली गई हैं। (यहां याद रखें कि फ़ाइल डिस्क्रिप्टर FILE * के समान नहीं हैं, लेकिन int मान हैं जो कर्नेल के बारे में जानता है)।इस आप कर सकते हैं करने से: आदेश शेल से

/bin/echo "hello world" > ./output_file.txt 

:

int X = open("./output_file.txt", O_WRONLY); 

pid_t fk = fork(); 
if (!fk) { /* in child */ 
    dup2(X, 1); /* fd 1 is standard output, 
        so this makes standard out refer to the same file as X */ 
    close(X); 

    /* I'm using execl here rather than exec because 
     it's easier to type the arguments. */ 
    execl("/bin/echo", "/bin/echo", "hello world"); 
    _exit(127); /* should not get here */ 
} else if (fk == -1) { 
    /* An error happened and you should do something about it. */ 
    perror("fork"); /* print an error message */ 
} 
close(X); /* The parent doesn't need this anymore */ 

यह चल रहा है पूरा करता है।

कार्यकारी में
16

कार्य() परिवार अलग व्यवहार है:

  • एल: तर्क मुख्य() को स्ट्रिंग की एक सूची के रूप में पारित कर रहे हैं
  • वी: तर्कों को तार की एक सरणी के रूप में पारित कर रहे हैं नई चल रहे प्रोग्राम के लिए खोज करने के लिए पथ/एस
  • ई: मुख्य()
  • पी पर्यावरण कॉल करने वाले को निर्दिष्ट किया जा सकता

आप उन्हें मिश्रण कर सकते हैं, इसलिए आपके पास है:

  • int execl (const char * path, const char * arg, ...);
  • int execlp (कॉन्स char * फ़ाइल, कॉन्स char * arg, ...);
  • int execle (const char * path, const char * arg, ..., char * const envp []);
  • int execv (const char * path, char * const argv []);
  • int execvp (कॉन्स char * फ़ाइल, char * const argv []);
  • int execvpe (कॉन्स char * फ़ाइल, char * const argv [], char * const envp []);

उन सभी के लिए प्रारंभिक तर्क एक फ़ाइल का नाम है जिसे निष्पादित किया जाना है।

man 3 exec # if you are running a UNIX system 
+0

दिलचस्प बात यह है कि आपने अपनी सूची से ['execve()'] (http://pubs.opengroup.org/onlinepubs/9699919799/functions/execve.html) को याद किया, जिसे POSIX द्वारा परिभाषित किया गया है, और आपने 'execvpe () ', जिसे पीओएसईक्स द्वारा परिभाषित नहीं किया गया है (ज्यादातर ऐतिहासिक उदाहरण के कारणों से; यह कार्यों के सेट को पूरा करता है)। अन्यथा, परिवार के लिए नामकरण सम्मेलन का एक सहायक स्पष्टीकरण - [paxdiablo] के लिए उपयोगी सहायक (https://stackoverflow.com/users/14860/paxdiablo) 'एक [उत्तर] (https://stackoverflow.com/a/4205020/15168) जो कार्यों के कामकाज के बारे में और बताता है। –

+0

और, आपकी रक्षा में, मुझे लगता है कि 'execvpe()' (et al) के लिए लिनक्स मैन पेज 'execve() 'सूचीबद्ध नहीं करता है; इसका अपना, अलग-अलग आदमी पृष्ठ (कम से कम उबंटू 16.04 एलटीएस पर) - अंतर यह है कि अन्य 'exec()' पारिवारिक फ़ंक्शंस अनुभाग 3 (फ़ंक्शंस) में सूचीबद्ध हैं जबकि 'execve() 'सेक्शन 2 में सूचीबद्ध है (सिस्टम कॉल)। असल में, परिवार में अन्य सभी कार्यों को 'execve() 'के कॉल के संदर्भ में लागू किया जाता है। –

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