2012-06-09 7 views
7

मैं कक्षा के लिए पाइपलाइनों के साथ एक खोल लागू करने के लिए संघर्ष कर रहा हूं। पाइप लाइन मेंसी ब्लॉक पर यूनिक्स पाइप पढ़ने पर

typedef struct { 
    char** cmd; 
    int in[2]; 
    int out[2]; 
} cmdio; 

cmdio cmds[MAX_PIPE + 1]; 

आदेश पढ़ सकते हैं और cmds में संग्रहीत हैं।

cmdio[i].in इनपुट पाइप के फ़ाइल डिस्क्रिप्टर की जोड़ी pipe() द्वारा लौटा दी गई है। पहले कमांड के लिए, जो टर्मिनल इनपुट से पढ़ता है, यह सिर्फ {fileno (stdin), -1} है। cmdin[i].out आउटपुट पाइप/टर्मिनल आउटपुट के लिए समान है। cmdio[i].incmd[i-1].out जैसा ही है। उदाहरण के लिए: process_command अंदर अब

for (cmdi = 0; cmds[cmdi].cmd != NULL; cmdi++) { 
    process_command(&cmds[cmdi]); 
} 

,:

$ ls -l | sort | wc 

CMD: ls -l 
IN: 0 -1 
OUT: 3 4 

CMD: sort 
IN: 3 4 
OUT: 5 6 

CMD: wc 
IN: 5 6 
OUT: -1 1 

हम process_command करने के लिए प्रत्येक आदेश है, जो चीजों के एक नंबर करता है पारित

if (!(pid_fork = fork())) { 
    dup2(cmd->in[0], fileno(stdin)); 
    dup2(cmd->out[1], fileno(stdout));  
    if (cmd->in[1] >= 0) { 
     if (close(cmd->in[1])) { 
      perror(NULL); 
     } 
    } 
    if (cmd->out[0] >= 0) { 
     if (close(cmd->out[0])) { 
      perror(NULL); 
     } 
    } 
    execvp(cmd->cmd[0], cmd->cmd); 
    exit(-1); 
} 

समस्या से पढ़ कि है पाइप ब्लॉक हमेशा के लिए:

COMMAND $ ls | wc 
Created pipe, in: 5 out: 6 
Foreground pid: 9042, command: ls, Exited, info: 0 
[blocked running read() within wc] 

हैं, तो execvp साथ प्रक्रिया का आदान प्रदान करने के बजाय, मैं सिर्फ ऐसा करते हैं:

if (!(pid_fork = fork())) { 
    dup2(cmd->in[0], fileno(stdin)); 
    dup2(cmd->out[1], fileno(stdout)); 
    if (cmd->in[1] >= 0) { 
     if (close(cmd->in[1])) { 
      perror(NULL); 
     } 
    } 
    if (cmd->out[0] >= 0) { 
     if (close(cmd->out[0])) { 
      perror(NULL); 
     } 
    } 

    char buf[6]; 
    read(fileno(stdin), buf, 5); 
    buf[5] = '\0'; 

    printf("%s\n", buf); 
    exit(0); 
} 

यह काम करने के लिए होता है:

COMMAND $ cmd1 | cmd2 | cmd3 | cmd4 | cmd5 
Pipe creada, in: 11 out: 12 
Pipe creada, in: 13 out: 14 
Pipe creada, in: 15 out: 16 
Pipe creada, in: 17 out: 18 
hola! 
Foreground pid: 9251, command: cmd1, Exited, info: 0 
Foreground pid: 9252, command: cmd2, Exited, info: 0 
Foreground pid: 9253, command: cmd3, Exited, info: 0 
Foreground pid: 9254, command: cmd4, Exited, info: 0 
hola! 
Foreground pid: 9255, command: cmd5, Exited, info: 0 

क्या हो सकता है समस्या?

उत्तर

4

आपके पास पर्याप्त बंद नहीं है। कोड में:

if (!(pid_fork = fork())) { 
    dup2(cmd->in[0], fileno(stdin)); 
    dup2(cmd->out[1], fileno(stdout));  
    if (cmd->in[1] >= 0) { 
     if (close(cmd->in[1])) { 
      perror(NULL); 
     } 
    } 
    if (cmd->out[0] >= 0) { 
     if (close(cmd->out[0])) { 
      perror(NULL); 
     } 
    } 
    close(cmd->in[0]); // Or your error checked version, but I'd use a function 
    close(cmd->out[1]);  
    execvp(cmd->cmd[0], cmd->cmd); 
    exit(-1); 
} 

कार्यक्रमों परिष्करण नहीं कर रहे हैं क्योंकि वहाँ:

if (!(pid_fork = fork())) { 
    dup2(cmd->in[0], fileno(stdin)); 
    dup2(cmd->out[1], fileno(stdout));  
    if (cmd->in[1] >= 0) { 
     if (close(cmd->in[1])) { 
      perror(NULL); 
     } 
    } 
    if (cmd->out[0] >= 0) { 
     if (close(cmd->out[0])) { 
      perror(NULL); 
     } 
    } 
    execvp(cmd->cmd[0], cmd->cmd); 
    exit(-1); 
} 

के बाद आप stdin और stdout (fileno() के माध्यम से) के लिए पाइप दोहराया गया है, तो आप पाइप बंद करने की आवश्यकता फ़ाइल का एक लेखन अंत अभी भी खुला है। साथ ही, यह न भूलें कि यदि पैरेंट प्रक्रिया (खोल) पाइप बनाता है, तो इसे पाइप के दोनों सिरों को बंद करना होगा। पाइप के साथ नलसाजी सीखना शुरू करते समय पर्याप्त पाइप बंद नहीं करना शायद सबसे आम गलती है।

+0

हम, काम नहीं करते हैं: \ यह अभी भी वही है, सिडिन/stdout को कमांड चलाने से पहले बंद हो जाता है, उदाहरण के लिए 'cat' 'cat: stdin: खराब फ़ाइल वर्णनकर्ता' के साथ विफल रहता है। लेकिन अगर मैं stdin/बाहर व्यवहार से बचने से बचने के लिए पहले जैसा ही है। जहां तक ​​मैं 'cmd -> (in | out) दोनों को समझता हूं [(0 | 1)]' उसी अंतर्निहित फ़ाइलों को 'fileno (std (in | out)' के रूप में संदर्भित करें, है ना? –

+0

खैर , प्रत्येक पाइप में एक पठन वर्णनकर्ता और एक लेखन वर्णनकर्ता होता है। जैसा कि मैं इसे समझता हूं, आपके पास माता-पिता और बच्चे (या दो बच्चों के बीच) के बीच दो पाइप हैं।प्रत्येक बच्चे की प्रक्रिया में, आप 'stdin' पर खुले एक पाइप के पढ़ने के अंत में केवल' dup2() 'और' stdout' पर खुले अन्य पाइप के लिखने के अंत के 'dup2()' चाहते हैं; पाइप के सभी मूल सिरों को बंद किया जाना चाहिए (जो लोगों को आश्चर्यचकित करता है)। मुझे यकीन नहीं है कि हमारे पास यह बताने के लिए पर्याप्त कोड है कि और क्या गलत हो रहा है। –

+0

धन्यवाद जोनाथन, मैं आपके जैसे माता-पिता से पाइप के दोनों सिरों को बंद नहीं कर रहा था। आपका बहुत बहुत धन्यवाद! –

1

ठीक है, मैंने अंततः इसे हल किया।

माता पिता प्रक्रिया पर, बस पूरे बच्चे कांटा के बाद, मैं डाल:

f (cmd->in[0] != fileno(stdin)) { 
    close(cmd->in[0]); 
    close(cmd->in[1]); 
} 

और देखा। मैंने पहले ऐसा कुछ किया था लेकिन मैंने गलत टाइप किया और close(cmd->out[0]); इसके बजाए किया। तो यह बात है। यह अब समझ में आता है।

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