管道和叉子导致错误和混乱的输出

时间:2017-03-12 06:50:05

标签: c arrays pipe fork

我在处理管道和子进程时遇到了一些问题。

我需要

  1. 使用fork()
  2. 创建四个孩子
  3. 使用父和每个孩子之间的pipe()建立双向通信
  4. 从包含字符串数的文件card.txt中读取数据
  5. 以循环方式将字符串分发给每个孩子 一个孩子得到A E,孩子2得到B F等等
  6. 选择一个成员变量 - >使用write()和read()以及close()关闭未使用的管道端
  7. 将变量发送到父级
  8. 在父进程中打印收到的变量
  9. 预期输出为:

    $ ./a.out 1C < card.txt
        Child : 1, pid 1593 : 
        <S2 S3 S9 ><H9 H6 HA H8 ><C6 CK ><D8 DQ D7 D3 >
        Child : 2, pid 1594 : 
        <SA S6 S7 S4 ><H4 HJ H7 ><CQ C9 CT ><DT D2 D9 >
        Child : 3, pid 1595 : 
        <SQ S5 ><H2 ><C7 C5 C8 CA C4 CJ C3 ><DA D5 > 
        Child : 4, pid 1596 : 
        <S8 SJ SK ST ><HK HT H5 H3 HQ ><C2 ><D4 D6 >
        child 1: H9 
        parent: child 1 played H9 
        child 2: CQ 
        parent: child 2 played CQ  
        child 3: H2
        parent: child 3 played H2 
        child 4: HK 
        parent: child 4 played HK 
    

    但实际输出如下:

    parent: child 1 played (null)parent: child 2 played (null)parent: child 3 played (null)parent: child 4 played (null)
    

    为什么?如何解决问题?

    代码创建了此输出:

    #include <stdio.h>
    #include <string.h>
    
    #define BUFFERSIZE 51 
     int i=0;
       int currpid, s; 
      char *buf[BUFFERSIZE]; 
        char *array[BUFFERSIZE];
        int n;
        char *buffer[100]; 
    /** child to parent pipe */
        int child_parent[2];
        /** parent to child pipe */
        int parent_child[2];
    
         /** child2 to parent pipe */
        int child2_parent[2];
        /** parent to child2 pipe */
        int parent_child2[2];
    
         /** child3 to parent pipe */
        int child3_parent[2];
        /** parent to child3 pipe */
        int parent_child3[2];
    
         /** child4 to parent pipe */
        int child4_parent[2];
        /** parent to child4 pipe */
        int parent_child4[2];
    
    void childFunction(){
        int j;
             for( i = s+1; i < BUFFERSIZE; i += 4 )
             {   
                buf[j] = array[i];  
                j++; 
             } 
             printf("\n<");
             int r;
             char *e;
             for( r = 0; r < j; r++ )
             { 
                int index;
                e = strchr(buf[r],'S');
                if (e!=NULL){
                    index = (int)(e-buf[r]);
                    if (index == 0){
    
                        printf("%s ", buf[r]) ; 
                    } 
                }  
            } 
            printf(">");
            printf("<");
            for( r = 0; r < j; r++ )
            { 
                int index;
                e = strchr(buf[r],'H');
                if (e!=NULL){
                    index = (int)(e-buf[r]);
                    if (index == 0){ 
                        printf("%s ", buf[r]) ; 
                    } 
                }  
            }   
            printf(">");
            printf("<");
            for( r = 0; r < j; r++ )
            { 
                int index;
                e = strchr(buf[r],'C');
                if (e!=NULL){
                    index = (int)(e-buf[r]);
                    if (index == 0){
                        printf("%s ", buf[r]) ; 
                    } 
                }  
            } 
            printf(">");
            printf("<");
            for( r = 0; r < j; r++ )
            { 
                int index;
                e = strchr(buf[r],'D');
                if (e!=NULL){
                    index = (int)(e-buf[r]);
                    if (index == 0){
                        printf("%s ", buf[r]) ; 
                    }
                }  
            } 
            printf(">\n");
            switch (s){
                case 0:
                  close(parent_child[1]);
                  close(parent_child[0]); 
                  close(child_parent[0]); 
                  buffer[0] = buf[0];
                  printf("child %d: %s", s+1, buffer[0]); 
                  write(child_parent[1], &buffer[0], strlen(buffer[0]));
                  close(child_parent[1]); 
                  break;
                case 1:
                  close(parent_child2[1]);
                  close(parent_child2[0]); 
                  close(child2_parent[0]); 
                  buffer[0] = buf[0];
                  printf("child %d: %s", s+1, buffer[0]); 
                  write(child2_parent[1], &buffer[0], strlen(buffer[0]));
                  close(child2_parent[1]); 
                  break;
                case 2:
                  close(parent_child3[1]);
                  close(parent_child3[0]); 
                  close(child3_parent[0]); 
                  buffer[0] = buf[0];
                  printf("child %d: %s", s+1, buffer[0]); 
                  write(child3_parent[1], &buffer[0], strlen(buffer[0]));
                  close(child3_parent[1]); 
                  break;
                case 3:
                  close(parent_child4[1]);
                  close(parent_child4[0]); 
                  close(child4_parent[0]); 
                  buffer[0] = buf[0];
                  printf("child %d: %s", s+1, buffer[0]); 
                  write(child4_parent[1], &buffer[0], strlen(buffer[0]));
                  close(child4_parent[1]); 
                  break;
            }
    } 
    void parentFunction(){
    
                    switch (s){
                        case 0:
                          close(child_parent[1]);
                          close(parent_child[1]);  
                          close(parent_child[0]);
                          read(child_parent[0],&buffer[0], sizeof(buffer[0])); 
                          printf("parent: child %d played %s", s+1, buffer[0]);
                          close(child_parent[0]);
                          break;
                         case 1:
                          close(child2_parent[1]);
                          close(parent_child2[1]);  
                          close(parent_child2[0]);
                          read(child2_parent[0],&buffer[0], sizeof(buffer[0])); 
                          printf("parent: child %d played %s", s+1, buffer[0]);
                          close(child2_parent[0]);
                          break;
                         case 2:
                          close(child3_parent[1]);
                          close(parent_child3[1]);  
                          close(parent_child3[0]);
                          read(child3_parent[0],&buffer[0], sizeof(buffer[0])); 
                          printf("parent: child %d played %s", s+1, buffer[0]);
                          close(child3_parent[0]);
                          break;
                         case 3:
                          close(child4_parent[1]);
                          close(parent_child4[1]);  
                          close(parent_child4[0]);
                          read(child4_parent[0],&buffer[0], sizeof(buffer[0])); 
                          printf("parent: child %d played %s", s+1, buffer[0]);
                          close(child4_parent[0]);
                          break;   
                    }
    }
    int main(int argc, char *argv[])
    {
        int ch; 
        ssize_t rread;
        char *line = NULL;
        size_t len = 0; 
        while (rread = getdelim( &line, &len, '\0', stdin) != -1) { 
        }  
    
        array[i] = strtok(line," ");
    
        while(array[i]!=NULL)
        {
            array[++i] = strtok(NULL," ");
        } 
    
        int childlimit = 4;
        int childpids[childlimit];
        int currpid; 
    
    
        if (pipe(child_parent) == 0 && pipe(parent_child) == 0 && pipe(child2_parent) == 0 && pipe(parent_child2) == 0 && pipe(child3_parent) == 0 && pipe(parent_child3) == 0 && pipe(child4_parent) == 0 && pipe(parent_child4) == 0)
        {
          for(s=0; s<childlimit; s++){
            switch(currpid = fork()){
            case 0: 
             printf("Child : %d, pid %d : ", s+1, getpid() );
             childFunction(); 
             break;
            case -1:
             printf("Error when forking\n");
             return 1;
            default:
            // in the father
            childpids[s] = currpid;  
            parentFunction();
            break;
            } 
              }   
        //wait for all child created to die
        waitpid(-1, NULL, 0); 
        }
    }
    

1 个答案:

答案 0 :(得分:1)

当您开始使用child2_parentparent_child2等名称时,会有一个数组试图逃离您的变量。当你有4组这些变量时,它是可怕的。

代码存在很多问题。这是一个完全重写。错误报告给stderr。检查大多数系统调用。已读取的数据的诊断打印输出。有一个函数split_string()可以将字符串拆分为空格中的单词。它在父组件和子组件中都使用。孩子们不再能够访问字符串数据 - 所有全局变量都已消失。

代码仍远未达到最佳状态。在开始孩子之前,没有特别需要打开所有管道;这个过程是同步的。依次为每个孩子创建管道是可行的,甚至是明智的。就目前而言,每个孩子只能关闭四分之一的可用管道描述符。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>

enum { MAX_KIDS  = 4 };
enum { LIST_SIZE = 1024 };
enum { MAX_WORDS = LIST_SIZE / 3 };

static int split_string(char *data, char *words[], int max_words)
{
    int num_words = 0;
    char *src = data;
    char *token;
    while ((token = strtok(src, " \n\t")) != NULL)
    {
        words[num_words++] = token;
        if (num_words >= max_words)
            break;
        src = NULL;
    }
    return num_words;
}

static void childFunction(int s, int f_pipe[2], int t_pipe[2])
{
    srand(getpid());
    close(f_pipe[1]);
    close(t_pipe[0]);
    char data[LIST_SIZE];
    int nbytes;
    if ((nbytes = read(f_pipe[0], data, sizeof(data))) <= 0)
    {
        fprintf(stderr, "child %d (PID %d): failed to read pipe\n", s, (int)getpid());
        exit(1);
    }
    data[nbytes] = '\0';
    close(f_pipe[0]);

    char *words[MAX_WORDS];
    int num_words = split_string(data, words, MAX_WORDS);
    char *word = words[rand() % num_words];
    int len = strlen(word);
    if (write(t_pipe[1], word, len) != len)
    {
        fprintf(stderr, "child %d (PID %d): failed to write [%s] to pipe\n", s, (int)getpid(), word);
        exit(1);
    }
    close(t_pipe[1]);
    exit(0);
}

static void parentFunction(int s, int c_pid, int t_pipe[2], int f_pipe[2], char *words[], int max_words)
{
    close(t_pipe[0]);
    close(f_pipe[1]);

    char buffer[LIST_SIZE];
    char *data = buffer;
    const char *pad = "";
    for (int i = s; i < max_words; i += MAX_KIDS)
    {
        int n = snprintf(data, (size_t)(buffer + sizeof(buffer) - data), "%s%s", pad, words[i]);
        data += n;
        pad = " ";
    }
    printf("Send [%s] to child %d\n", buffer, s);

    /* Write list of words to child */
    int nbytes = data - buffer;
    if (write(t_pipe[1], buffer, nbytes) != nbytes)
    {
        fprintf(stderr, "parent: failed to write to child %d (PID %d)\n", s, c_pid);
        exit(1);
    }
    close(t_pipe[1]);

    /* Read selected word from child */
    nbytes = read(f_pipe[0], buffer, sizeof(buffer));
    if (nbytes <= 0)
    {
        fprintf(stderr, "parent: failed to read from child %d (PID %d)\n", s, c_pid);
        exit(1);
    }
    buffer[nbytes] = '\0';
    close(f_pipe[0]);

    printf("parent: child %d (PID %d) played %s\n", s, c_pid, buffer);
}

int main(void)
{
    ssize_t rread;
    char *line = NULL;
    size_t len = 0;
    if ((rread = getdelim(&line, &len, '\0', stdin)) == -1)
    {
        fprintf(stderr, "Unexpected EOF on standard input\n");
        return 1;
    }

    printf("line [%s]\n", line);

    char *wordlist[MAX_WORDS];
    int num_words = split_string(line, wordlist, MAX_WORDS);

    printf("Word list:");
    int i;
    for (i = 0; i < num_words; i++)
    {
        if (i % 10 == 0 && i > 0)
            printf("%10s", "");
        printf(" %2d [%s]", i, wordlist[i]);
        if (i % 10 == 9)
            putchar('\n');
    }
    if (i % 10 != 0)
        putchar('\n');
    printf("%d words\n", i);

    for (int kid = 0; kid < MAX_KIDS; kid++)
    {
        printf("Words for child %d:", kid);
        for (int word = kid; word < i; word += MAX_KIDS)
            printf(" [%s]", wordlist[word]);
        putchar('\n');
    }

    int child_parent[MAX_KIDS][2];
    int parent_child[MAX_KIDS][2];

    for (int i = 0; i < MAX_KIDS; i++)
    {
        if (pipe(child_parent[i]) != 0 || pipe(parent_child[i]) != 0)
        {
            fprintf(stderr, "failed to create pipes for child %d\n", i);
            exit(1);
        }
    }

    for (int s = 0; s < MAX_KIDS; s++)
    {
        int currpid = fork();
        if (currpid < 0)
        {
            fprintf(stderr, "Error when forking\n");
            exit(1);
        }
        else if (currpid == 0)
        {
            printf("Child : %d, pid %d:\n", s, getpid() );
            childFunction(s, parent_child[s], child_parent[s]);
        }
        else
            parentFunction(s, currpid, parent_child[s], child_parent[s], wordlist, num_words);
    }

    int corpse;
    int status;
    while ((corpse = waitpid(-1, &status, 0)) > 0)
        printf("PID %d died with exit status 0x%.4X\n", corpse, status);
}

给定一个数据文件:

S2 SA SQ S8 S3 S6 S5 SJ S9 S7 H2 SK H9 S4 C7
ST H6 H4 C5 HK HA HJ C8 HT H8 H7 CA H5 C6 CQ
C4 H3 CK C9 CJ HQ D8 CT C3 C2 DQ DT DA D4 D7
D2 D5 D6 D3 D9

该程序的一个示例输出是:

line [S2 SA SQ S8 S3 S6 S5 SJ S9 S7 H2 SK H9 S4 C7
ST H6 H4 C5 HK HA HJ C8 HT H8 H7 CA H5 C6 CQ
C4 H3 CK C9 CJ HQ D8 CT C3 C2 DQ DT DA D4 D7
D2 D5 D6 D3 D9
]
Word list:  0 [S2]  1 [SA]  2 [SQ]  3 [S8]  4 [S3]  5 [S6]  6 [S5]  7 [SJ]  8 [S9]  9 [S7]
           10 [H2] 11 [SK] 12 [H9] 13 [S4] 14 [C7] 15 [ST] 16 [H6] 17 [H4] 18 [C5] 19 [HK]
           20 [HA] 21 [HJ] 22 [C8] 23 [HT] 24 [H8] 25 [H7] 26 [CA] 27 [H5] 28 [C6] 29 [CQ]
           30 [C4] 31 [H3] 32 [CK] 33 [C9] 34 [CJ] 35 [HQ] 36 [D8] 37 [CT] 38 [C3] 39 [C2]
           40 [DQ] 41 [DT] 42 [DA] 43 [D4] 44 [D7] 45 [D2] 46 [D5] 47 [D6] 48 [D3] 49 [D9]
50 words
Words for child 0: [S2] [S3] [S9] [H9] [H6] [HA] [H8] [C6] [CK] [D8] [DQ] [D7] [D3]
Words for child 1: [SA] [S6] [S7] [S4] [H4] [HJ] [H7] [CQ] [C9] [CT] [DT] [D2] [D9]
Words for child 2: [SQ] [S5] [H2] [C7] [C5] [C8] [CA] [C4] [CJ] [C3] [DA] [D5]
Words for child 3: [S8] [SJ] [SK] [ST] [HK] [HT] [H5] [H3] [HQ] [C2] [D4] [D6]
Send [S2 S3 S9 H9 H6 HA H8 C6 CK D8 DQ D7 D3] to child 0
Child : 0, pid 89366:
parent: child 0 (PID 89366) played HA
Send [SA S6 S7 S4 H4 HJ H7 CQ C9 CT DT D2 D9] to child 1
Child : 1, pid 89367:
parent: child 1 (PID 89367) played S4
Send [SQ S5 H2 C7 C5 C8 CA C4 CJ C3 DA D5] to child 2
Child : 2, pid 89368:
parent: child 2 (PID 89368) played C5
Send [S8 SJ SK ST HK HT H5 H3 HQ C2 D4 D6] to child 3
Child : 3, pid 89369:
parent: child 3 (PID 89369) played D6
PID 89368 died with exit status 0x0000
PID 89367 died with exit status 0x0000
PID 89366 died with exit status 0x0000
PID 89369 died with exit status 0x0000