Tricky pipes

I have written a demo program for pipes.

A process forks, the parent writes a number to pipe, the child reads it, divides by 2, and sends it back. The parent reads the number and prints it.

#include <stdio.h>

#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>

#define COLOR_YELLOW "33[1;33m"
#define COLOR_GREEN "33[1;32m"
#define COLOR_RED "33[1;31m"
#define COLOR_CLEAR "33[0m"

int main(int argc, char *argv[])
{
        printf(COLOR_YELLOW "Let the story begin\n");
	printf("I am a parent, my pid = %d\n", getpid());

	char c;
	int pipes[2];
	int child_pid;
	pipe(pipes);
	printf("I have two pipes: %d %d\n", pipes[0], pipes[1]);
	printf(COLOR_CLEAR);

	child_pid = fork();
	if (child_pid > 0) {
		printf(COLOR_GREEN "I am still a parent, my pid = %d\n"COLOR_CLEAR, getpid());

		int f_random = open("/dev/urandom", O_RDONLY);
		read(f_random, &c, 1);
		close(f_random);

		printf(COLOR_GREEN"I read a random number `%d' and send it to pipes[1]\n"COLOR_CLEAR, (int)c);
		write(pipes[1], &c, 1);
		c = 0;

		printf(COLOR_GREEN"Now I wait for a response from pipes[0]\n"COLOR_CLEAR);
		read(pipes[0], &c, 1);
		printf(COLOR_GREEN "I have read number `%d'. Good night, sweet pipes.\n"COLOR_CLEAR, (int)c);
	} else {
		printf(COLOR_RED "I am a child, my pid = %d\n" COLOR_CLEAR, getpid());

		read(pipes[0], &c, 1);
		printf(COLOR_RED "I read a number `%d' from pipes[0]\n"COLOR_CLEAR, (int)c);

		printf(COLOR_RED "Then I slowly divide it by 2 and send it to pipes[1]\n"COLOR_CLEAR);
		c /= 2;
		sleep(5);
		write(pipes[1], &c, 1);

		printf(COLOR_RED "And that's my farewell.\n"COLOR_CLEAR);
	}
	close(pipes[0]);
	close(pipes[1]);

        return 0;
}

But usually the child exits without reading a number, and the parent reads the number it has just written:

$ ./pipe
Let the story begin
I am a parent, my pid = 1545
I have two pipes: 3 4
I am still a parent, my pid = 1545
I am a child, my pid = 1546
I read a random number `119' and send it to pipes[1]
Now I wait for a response from pipes[0]
I have read number `119'. Good night, sweet pipes.

If I trace it with strace, the demo works as it should.

Any idea?

Advertisements

2 responses to “Tricky pipes

  1. First, wordpress kindly ate indentation and color strings, which makes your code harder to read and try running.

    Second, you’ve got race between parent reading from pipe and child starting and reading from pipe. According to pipe(7), pipes always have some internal buffer, and write(2) will not block unless the buffer is full. You’ll have to create two pipes or use other synchronization facilities to make parent and child communicate reliably.

  2. 1. That’s why I prefer C to Python 😉 Spaces and newlines are too volatile.
    2. Exactly! I was waiting for two key phrases from my readers: “race condition” and “single buffer”.

    Thank you for reading my blog, Ivan!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s