Richie Thomas
Richie Thomas

Reputation: 3255

With vs without the C pipe() function- what's causing this behavior?

I wrote a simple script (taken from a tutorial) which writes data to one end of a pipe in a child process, and reads it from the other end of the pipe in the parent process:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>

int main()
{
  pid_t pid;
  int mypipefd[2];
  int ret;
  char buf[20];

  ret = pipe(mypipefd);

  if (ret == -1) {
    printf("Pipe failed.\n");
    exit(1);
  }

  if ((pid = fork()) == -1) {
    printf("Fork failed.\n");
    exit(1);
  } else if (pid == 0) {
    printf("Child process.\n");
    char msg[] = "Hello there!";
    write(mypipefd[1], msg, strlen(msg) + 1); 
  } else {
    printf("Parent process.\n");
    read(mypipefd[0], buf, 15);
    printf("Buf: %s\n", buf);
  }

  return 0;
}

This works fine and outputs the results I expect:

Parent process.
Child process.
Buf: Hello there!
[ project ] $

Then as I got more familiar with the code, I wondered why we need to use mypipefd[2] and pipe() to achieve this goal, or whether mypipefd[1] by itself would work. So I tried it out with the following code:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>

int main()
{
  pid_t pid;
  int my_array[1];
  char buf[20];

  if ((pid = fork()) == -1) {
    printf("Fork failed.\n");
    exit(1);
  } else if (pid == 0) {
    printf("Child process.\n");
    char msg[] = "Hello there!\n";
    write(my_array[0], msg, strlen(msg) + 1); 
  } else {
    // wait(NULL);
    printf("Parent process.\n");
    read(my_array[0], buf, 15);
    printf("Buf: %s\n", buf);
  }

  return 0;
}

This code outputs the same text, but it hangs after it finishes printing.

Parent process.
Child process.
Buf: Hello there!

No prompt, this time. I even tried un-commenting that call to wait(NULL), on the off-chance that the root cause was a conflict between parent and child processes. No such luck.

What's going on here? Why am I unable to read and write to a length-of-one array in this way without the program hanging? What exactly is the compiler stuck on?

Upvotes: 1

Views: 510

Answers (2)

nivpeled
nivpeled

Reputation: 1838

The pipe() function accepts an array of 2 integer as an input argument.

#include <unistd.h>
int pipe(int pipefd[2]);
#define _GNU_SOURCE             /* See feature_test_macros(7) */
#include <fcntl.h>              /* Obtain O_* constant definitions */
#include <unistd.h>
int pipe2(int pipefd[2], int flags);

It then generates a new pipe object, and initializes the pipefd array with file descriptors for read and write operation.

What you try to do is call read() and write() using some arbitrary, uninitialized ints (or file descriptor). Meaning the OS did not allocate a pipe object and did not provide you with file descriptors (the pipe's API) to be use with read() and write().

This (calling read() or write() with uninitialized file descriptor) will result in "undefined behavior".

"I find that a good working definition of "undefined behaviur" is "works for me, works for you, works during development and QA, but blows up in your most important customer's face"" --- Scott Meyers

Upvotes: 1

Some programmer dude
Some programmer dude

Reputation: 409136

A pipe, on computers as well as in real life, have two ends. And like pipes in real life, data flows from one end of the pipe (the write end) to the other (the read end).

The pipe function gives you those two ends by writing them to an array of two file-descriptors. The first element of the pair is read-only, and the second is write-only.

Upvotes: 1

Related Questions