2009-02-13 10 views
18

के साथ शुरू की गई प्रक्रिया को मारें popen के साथ एक प्रक्रिया में पाइप खोलने के बाद, क्या प्रक्रिया शुरू करने के लिए कोई तरीका है? (pclose का उपयोग करना मैं नहीं चाहता क्योंकि यह प्रक्रिया समाप्त होने की प्रतीक्षा करेगा, लेकिन मुझे इसे मारने की ज़रूरत है।)पॉपन

उत्तर

24

पॉपन() का उपयोग न करें, और अपना खुद का रैपर लिखें जो आप चाहते हैं।

यह फोर्क() के लिए काफी सरल है, और उसके बाद stdin & stdout को dup2() का उपयोग करके और फिर अपने बच्चे पर exec() को कॉल करके प्रतिस्थापित करें।

इस तरह, आपके माता-पिता के पास सटीक बच्चा पीआईडी ​​होगा, और आप उस पर हत्या() का उपयोग कर सकते हैं।

पर कुछ नमूना कोड के लिए "popen2() कार्यान्वयन" के लिए Google खोज क्या popen() कर रहा है। यह केवल एक दर्जन या तो लाइन लंबा है। dzone.com से लिया हम एक उदाहरण है कि इस तरह दिखता है देख सकते हैं:

#define READ 0 
#define WRITE 1 

pid_t 
popen2(const char *command, int *infp, int *outfp) 
{ 
    int p_stdin[2], p_stdout[2]; 
    pid_t pid; 

    if (pipe(p_stdin) != 0 || pipe(p_stdout) != 0) 
     return -1; 

    pid = fork(); 

    if (pid < 0) 
     return pid; 
    else if (pid == 0) 
    { 
     close(p_stdin[WRITE]); 
     dup2(p_stdin[READ], READ); 
     close(p_stdout[READ]); 
     dup2(p_stdout[WRITE], WRITE); 

     execl("/bin/sh", "sh", "-c", command, NULL); 
     perror("execl"); 
     exit(1); 
    } 

    if (infp == NULL) 
     close(p_stdin[WRITE]); 
    else 
     *infp = p_stdin[WRITE]; 

    if (outfp == NULL) 
     close(p_stdout[READ]); 
    else 
     *outfp = p_stdout[READ]; 

    return pid; 
} 

एनबी: popen2 की तरह लगता है(), तुम क्या चाहते है, लेकिन मेरे वितरण इस विधि के साथ आने के लिए प्रतीत नहीं होता।

+0

यह कांटा की स्मृति डुप्लिकेशन के मुद्दे को हल नहीं करता है। यह संभव है कि हम इस कारण से फोर्क को कॉल नहीं करना चाहते हैं – Will

+0

@ फ़ूजी क्या पाइथन को कुछ भी करना है? –

+0

@ महमूद अल-कुडसी: हुप्स। मैं बहुत सारे पायथन सवालों पर लूटा हुआ होगा। [इससे पहले पायथन से संबंधित टिप्पणी फिर से प्रतिक्रिया दी गई थी] – phooji

0

स्पष्ट तरीका सिस्टम ("pkill process_name") है;

स्पष्ट रूप से यह समस्याग्रस्त है यदि आपके पास प्रक्रिया के एक से अधिक उदाहरण हैं।

+0

यह वह मामला है जहां कई उदाहरण चल रहे हैं और किसी को एक सटीक उदाहरण को लक्षित करने की आवश्यकता है। – jldupont

4

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

3

असल प्रक्रिया आई/ओ कर अगर है (जो यह होना चाहिए, नहीं तो क्यों popensystem के बजाय (3)?), तो pclose यह एक SIGPIPE साथ अगली बार पढ़ने या लिखने की कोशिश करता है अजीब चाहिए, और यह अच्छी तरह से गिरना चाहिए :-)

0

मैंने पाइथन में कुछ ऐसा किया, जहां आप इसके लिए एक उपप्रजाति और किसी भी उपप्रजाय को मार सकते थे। यह वास्तव में स्लेसी के समाधान के समान है। http://www.pixelbeat.org/libs/subProcess.py

5

यहां popen2 का एक बेहतर संस्करण है (क्रेडिट सर्गेई एल के कारण है)। स्लेसी द्वारा पोस्ट किया गया संस्करण popen2 में बनाई गई प्रक्रिया के पीआईडी ​​को वापस नहीं करता है, लेकिन पीआईडी ​​sh को असाइन किया गया है।

pid_t popen2(const char **command, int *infp, int *outfp) 
{ 
    int p_stdin[2], p_stdout[2]; 
    pid_t pid; 

    if (pipe(p_stdin) != 0 || pipe(p_stdout) != 0) 
     return -1; 

    pid = fork(); 

    if (pid < 0) 
     return pid; 
    else if (pid == 0) 
    { 
     close(p_stdin[WRITE]); 
     dup2(p_stdin[READ], READ); 
     close(p_stdout[READ]); 
     dup2(p_stdout[WRITE], WRITE); 

     execvp(*command, command); 
     perror("execvp"); 
     exit(1); 
    } 

    if (infp == NULL) 
     close(p_stdin[WRITE]); 
    else 
     *infp = p_stdin[WRITE]; 

    if (outfp == NULL) 
     close(p_stdout[READ]); 
    else 
     *outfp = p_stdout[READ]; 

    return pid; 
} 

नए संस्करण मैं @slacy के विचार का पालन कि समारोह popen2 बनवाने के

char *command[] = {"program", "arg1", "arg2", ..., NULL}; 
+0

मैंने पिड भाग में कोई अंतर नहीं देखा; क्या आप अंतर भाग पर टिप्पणियां अपडेट कर सकते हैं। – nayab

+0

आपके संस्करण के लिए धन्यवाद शतरंज, वास्तव में अच्छा! –

0

साथ कहा जा रहा है।
लेकिन बच्चे की प्रक्रिया मरने पर समस्या मिली, मूल प्रक्रिया जो अभी भी फ़ाइल descripter outfp फ़ंक्शन से वापस नहीं पढ़ती है।

जो माता-पिता प्रक्रिया पर नज़दीकी अप्रयुक्त पाइप जोड़कर ठीक हो सकता है।

close(p_stdin[READ]); 
close(p_stdout[WRITE]); 

हम शेल के रूप में पार्टी का उपयोग करके नई प्रक्रिया का सही पीआईडी ​​मिल सकती है।

execl("/bin/bash", "bash", "-c", command, NULL); 

बच्चे प्रक्रिया समारोह popen2 के फोन करने वाले कॉल pclose2 द्वारा बच्चे प्रक्रिया की स्थिति एकत्र करना चाहिए मरना है। अगर हम उस स्थिति को एकत्र नहीं करते हैं तो यह प्रक्रिया समाप्त होने पर ज़ोंबी प्रक्रिया हो सकती है।

यह पूरा कोड है जो परीक्षण के रूप में परीक्षण और काम करता है।

#define READ 0 
#define WRITE 1 

pid_t 
popen2(const char *command, int *infp, int *outfp) 
{ 
    int p_stdin[2], p_stdout[2]; 
    pid_t pid; 

    if (pipe(p_stdin) != 0 || pipe(p_stdout) != 0) 
     return -1; 

    pid = fork(); 

    if (pid < 0) 
     return pid; 
    else if (pid == 0) 
    { 
     dup2(p_stdin[READ], STDIN_FILENO); 
     dup2(p_stdout[WRITE], STDOUT_FILENO); 

    //close unuse descriptors on child process. 
    close(p_stdin[READ]); 
    close(p_stdin[WRITE]); 
    close(p_stdout[READ]); 
    close(p_stdout[WRITE]); 

     //can change to any exec* function family. 
     execl("/bin/bash", "bash", "-c", command, NULL); 
     perror("execl"); 
     exit(1); 
    } 

    // close unused descriptors on parent process. 
    close(p_stdin[READ]); 
    close(p_stdout[WRITE]); 

    if (infp == NULL) 
     close(p_stdin[WRITE]); 
    else 
     *infp = p_stdin[WRITE]; 

    if (outfp == NULL) 
     close(p_stdout[READ]); 
    else 
     *outfp = p_stdout[READ]; 

    return pid; 
} 

int 
pclose2(pid_t pid) { 
    int internal_stat; 
    waitpid(pid, &internal_stat, 0); 
    return WEXITSTATUS(internal_stat); 
} 
0

मैं बस (बैश) स्क्रिप्ट में डाल पहली पंक्ति में:

echo PID $$ 

तो मैं पीआईडी ​​पढ़ सकते हैं और इसका इस्तेमाल करने के लिए एक: मार (पीआईडी, 9)

+0

पॉपन शुरू करने के लिए चीज है, यह चीज समस्या के लिए एक अच्छा प्यारा समाधान है। – stu