简体   繁体   English

为什么不能写入管道或从管道读取?

[英]Why can't I write to or read from pipes?

I've seen a lot of similar questions, but all of them addressed specific cases and did not assist me in finding a solution. 我已经看到了很多类似的问题,但是所有这些问题都针对特定的情况,因此没有帮助我找到解决方案。 I would appreciate any feedback on my situation, which is as follows: 对于我的情况,请提供以下反馈:

I am trying to write a program to get character counts from a text file. 我正在尝试编写一个程序来从文本文件中获取字符数。 The program works by forking four mappers and 26 reducers, and creating pipes for each of them. 该程序通过派生四个映射器和26个reducer并为它们中的每个创建管道来工作。 The parent process separates the input into four lines and passes one to each mapper, which counts the number of each character in its line. 父进程将输入分为四行,然后将其传递给每个映射器,该映射器计算其行中每个字符的数量。 Each mapper then passes the counts on to the appropriate reducers, which sum up all four counts and print the result. 然后,每个映射器将计数传递到适当的缩减器,后者对所有四个计数求和并打印结果。

Below is my code thus far: 以下是到目前为止的代码:

 int main(int argc, char *argv[])
{
  int i = 0;

  FILE *input = fopen("input.txt", "r");

  // Things for reading line-by-line: see getline reference on man7.org
  char *line = NULL;
  size_t len = 0;

  // Where we'll store the messages
  static char message[MSGSIZE];

  for(i = 0; i < NUMREDUCERS; i++)
    {
      pipe(reducer_pipes[i]);
    }

  for(i = 0; i < NUMMAPS; i++)
    {
      // Step 1: Create pipes for communication using the system call pipe()
      pipe(mapper_pipes[i]);

      // Step 2: Fork a number of mappers (4).
      if (fork() == 0)
    {
      // Don't want to close the write pipe yet
      // Child process: one of the mappers

      read(mapper_pipes[i][0], message, MSGSIZE); // Read from reading end
      char *msg = "Error reading from pipe";
      check_errors(msg);

      // Get char count and write to pipe
      int j = 0;
      int ccount = 0;
      for(j = 0; j < NUMREDUCERS; j++)
        {
          // Count up the number of chars
          ccount = count_char(message, (char) (j + 97), MSGSIZE);

          // Write to the appropriate reducer pipe
          write(reducer_pipes[j][1], (char *) ccount, MSGSIZE);
          msg = "error writing to reducer pipe";
          check_errors(msg);

        }

      exit(EXIT_SUCCESS);
    }
      else
    {
      getline(&line, &len, input);
      // Parent process

      write(mapper_pipes[i][1], line, (int) len);
      char *msg = "Error writing to pipe";
      check_errors(msg);
    }
    }

  return 0;
}

The problem I am encountering is that I cannot write to the reducer pipes. 我遇到的问题是我无法写入减速器管道。 I get a bad address error whenever I attempt to write to, read from, or close them. 每当我尝试写入,读取或关闭它们时,我都会收到一个错误的地址错误。 Did they somehow expire? 他们以某种方式到期了吗? Did I not create them correctly? 我没有正确创建它们吗? If anyone has input to offer, I would greatly appreciate it. 如果有人愿意提供意见,我将不胜感激。

Quick edit: I have removed all of my "close" statements, as they had the same issue. 快速编辑:我删除了所有“关闭”语句,因为它们都存在相同的问题。 I have, however, tried closing the pipes where they should be closed, only to find the same error message. 但是,我尝试关闭应该关闭管道的位置,只是找到了相同的错误消息。

"Bad address" ( errno == EFAULT ) means you have passed an invalid pointer to a system call. “地址errno == EFAULT ”( errno == EFAULT )表示您已将无效指针传递给系统调用。 It's essentially the equivalent of a segfault (I believe some systems actually just raise SIGSEGV in this situation). 从本质上讲,它相当于一个段错误(我相信某些系统实际上在这种情况下会提高SIGSEGV )。

Look at this line: 看这行:

      write(reducer_pipes[j][1], (char *) ccount, MSGSIZE);

Here ccount is of type int. 这里的ccount是int类型的。 Casting an int to a pointer is always suspicious. 将int转换为指针始终是可疑的。

In the previous line, you assigned ccount to the return value of count_char() . 在上一行中,您ccount分配给count_char()的返回值。 Now you didn't show us the code for that function, but I'm going to guess it returns a count of characters - most likely a small integer. 现在您没有向我们展示该函数的代码,但是我想它会返回一个字符数-最有可能是一个小整数。 Let's say it returned 17. You are telling write to write MSGSIZE bytes which are located at address 17. That is assuredly not what you want. 假设它返回了17。您正在告诉write写入位于地址17的MSGSIZE字节。这肯定不是您想要的。

If you wanted to send that integer to the reducer, in binary format, you probably wanted to say 如果您想以二进制格式将该整数发送给reducer,您可能想说

write(reducer_pipes[j][1], &ccount, sizeof(ccount));

And of course you'll have to have matching code on the reducer side. 当然,您必须在减速器端具有匹配的代码。


Other people have addressed a number of other issues in your code, such as the fact that you can't reliably detect errors just by looking at errno (which presumably is what check_errors does). 其他人已经解决了代码中的许多其他问题,例如您仅通过查看errno就无法可靠地检测错误(这大概就是check_errors所做的事情)。 If a system call doesn't have an error, it leaves errno untouched, even if it had a nonzero value previously. 如果系统调用没有错误,则即使先前具有非零值,也不会errno What you should do instead is check the return value from write() ; 相反,您应该做的是检查write()的返回值; if it is -1 then an error occurred and only then should you look at errno (or call perror ) to see what it was. 如果它是-1那么将发生错误,只有这样,您才应该查看errno (或致电perror )以查看其含义。

Basically, any time you make a system call and don't check the return value, you have a bug. 基本上,每当您进行系统调用并且不检查返回值时,都会遇到错误。

You don't show what your check_errors function is, but I would guess it is just printing an error message without actually checking for errors, under the assumption that you only call it after an error. 您没有显示您的check_errors函数是什么,但是我猜想它只是在显示错误消息而没有实际检查错误的情况下,假设您仅在发生错误后才调用它。 So you might not actually be getting an error. 因此,您实际上可能并没有收到错误消息。

You need to actually check the return value of your read and write calls to see if an error occured: 您实际上需要检查读写调用的返回值,以查看是否发生错误:

if ((len = read(mapper_pipes[i][0], message, MSGSIZE)) < 0) // Read from reading end
    perror("Error reading from pipe");

Note that the return value also tells you the length of the message received if there isn't an error (and you should use that instead of MSGSIZE in the subsequent code that looks at the message. 请注意,如果没有错误,返回值还会告诉您接收到的消息的长度(您应该在查看该消息的后续代码中使用该值代替MSGSIZE

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM