【问题标题】:Multiprocess, Forks and Pipes in CC 中的多进程、分叉和管道
【发布时间】:2012-11-04 21:47:41
【问题描述】:

我之前发布了一个关于using fork() and pipes in C 的问题。我稍微改变了设计,让它读取一个常规的 txt 文件并对文件中的单词进行排序。到目前为止,这是我想出的:

 for (i = 0; i < numberOfProcesses; ++i) {
    // Create the pipe
    if (pipe(fd[i]) < 0) {
      perror("pipe error");
      exit(1);
    }

    // fork the child
    pids[i] = fork();
    if (pids[i] < 0) {
      perror("fork error");
    } else if (pids[i] > 0) {     
      // Close reading end in parent
      close(fd[i][0]);

    } else {     
      // Close writing end in the child
      close(fd[i][1]);

      int k = 0;
      char word[30];

      // Read the word from the pipe
      read(fd[i][0], word, sizeof(word));

      printf("[%s]", word);    <---- **This is for debugging purpose**

     // TODO: Sort the lists  
    }
  }


  // Open the file, and feed the words to the processes
  file_to_read = fopen(fileName, "rd");

  char read_word[30];
  child = 0;

  while( !feof(file_to_read) ){
    // Read each word and send it to the child
    fscanf(file_to_read," %s",read_word);

    write(fd[child][1], read_word, strlen(read_word));
    ++child;
    if(child >= numberOfProcesses){
      child = 0;
    }
  }

其中numberOfProcesses 是命令行参数。所以它的作用是读取文件中的每个单词并将其发送到一个进程。然而,这不起作用。当我在子进程中打印单词时,它没有给我正确的输出。我是否正确地从管道中写入/读取单词?

【问题讨论】:

    标签: c fork pipe


    【解决方案1】:

    是否以错误的顺序打印单词或交错?问题是,当您向管道写入一个单词时,您期望处理该管道的进程立即安排并打印该单词。然后您希望主进程再次运行,并将下一个单词写入下一个管道等。

    但这并不保证会发生。您的主循环可能会在安排任何其他进程之前将所有单词写入所有管道。这些过程可能不会按照您期望的顺序安排。而且 printf 调用可能会相互干扰,从而导致它们的输出交错。

    如果你真的想做你想做的事,那么 Posix 线程会更好。如果你只是想学习一些关于使用多个进程的知识,那么我猜你有:-)

    【讨论】:

    • 我强烈怀疑这是主要问题 - 你绝对需要同步你的并发进程,否则输出将相互“交错”(即“加扰”)。
    • 嗯,这是一个作业。我对 C 语言编程和在 Linux 环境中工作都很陌生。所以是的,我必须用流程来做这件事。用 C# 编写它需要不到 2 小时。但是请注意,我使用 Emacs 作为编辑器,而不是 Visual Studio,所以整个调试过程是一场噩梦。
    • @programmer93 如果你习惯了 IDE,你不妨使用 Eclipse 和 CDT。
    • ...或在 Emacs 下运行 gdb - alt-x gdb
    • @WilliamMorris 即使他会使用线程,他也需要同步它们。
    【解决方案2】:

    在父级中,您写入 strlen() 字节,可能小于 30 字节。但是,在孩子中,您总是尝试读取 30 个字节。您还必须以 NUL 终止单词,否则您可能会在 printf() 语句中看到垃圾或失控字符串。

    在孩子中,您必须在单词边界解析和拆分输入,或者按照@JonathanLeffler 的建议使用 stdio。当您使用 stdio 时,您可以免费获得所有这些缓冲和单词阅读。

    int n;
    char word[31];
    
    /* Read the word from the pipe */
    n = read(fd[i][0], word, sizeof(word) - 1);
    if (n == -1) {
        perror("read");
        /* do error handling */
    } else {
        word[n] = 0;
        printf("[%s]", word);
    }
    

    【讨论】:

    • “在单词边界解析和拆分输入”是什么意思?
    • 您必须在输入缓冲区(单词)中查找空白并在那里拆分字符串。然后将剩余的字节作为下一个单词的输入。另请注意,读取可能会返回 30 个字节或更少,因此请检查返回值。
    • 好吧,我的输入中没有任何空格。例如,这是我的文本文件:Hello this is a sample text file this file has three lines this is the third line 但是当我运行程序时,3 个进程的输出是这样的:[Helloafilehasthisthird][istextfilelinesthe][thissamplethisthreeislinethiss][Helloafilehasthisthird] 等等。
    • 这是因为三个进程不同步。这就像一群人同时在说话。
    • @programmer93 看看我修改后的答案。您必须以 NUL 结束单词。您获得的输出可能包括以前读取的部分内容。但我强烈建议,你再看看乔纳森的解决方案。
    猜你喜欢
    • 2013-11-18
    • 2023-03-16
    • 2010-12-14
    • 1970-01-01
    • 1970-01-01
    • 2019-04-07
    • 2013-11-10
    • 1970-01-01
    相关资源
    最近更新 更多