1

I've written a simple reader-writer pair of programs. Writer creates/opens a FIFO-file and is constantly writing a string into it. The reader is just reading it and writing to stdout. The reader does so only for 10 times and then quits. Surprisingly (for me) the writer almost immediately exits too. It does not just go out of writing loop, it seems to jump out of it, I can tell it by not seeing the final "byebye" on the screen. I could sort of accept such behaviour, but I still can't understand why. Could someone please kindly share their knowledge with me?

/* writer code */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>

int main()
{
    char msg [] = "Leo_Tolstoy";

    size_t len = strlen("Leo_Tolstoy");

    if (mkfifo ("myfifo", 0600) != 0) {
        perror ("creating fifo");
    }
    int fd;
    if ( (fd = open ("myfifo", O_WRONLY)) == -1) {
        perror ("opening fifo");
        exit (1);
    }
    while (1)
    {
        int r = write (fd, msg, len);
        if (r == -1)
            perror ("writing");
        sleep(1);
    }
    printf ("byebye\n");
    close (fd);
    return 0;
}
/* reader code */
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/shm.h>

int main()
{
    char buf[50];

    printf ("bef opening\n");
    int fd = open ("myfifo", O_RDONLY);
    if (fd == -1) {
        perror ("opening fifo");
        exit (1);
    }

    printf ("bef reading\n");
    int cnt=0;
    while (cnt < 10)
    {
        int r = read (fd, buf, 50);
        if (r == 0)
            break;
        if (r == -1)
            perror ("reading");
        write (1, buf, r);
        cnt++;
    }
//  close (fd);
    return 0;
}
too honest for this site
  • 12,050
  • 4
  • 30
  • 52
daniel.kish
  • 95
  • 1
  • 10
  • 1
    So, C or C++. I would say C, but that's your call. Please choose *one* language, not 2 (your question doesn't seem to apply to different languages). – Rakete1111 Aug 23 '16 at 18:47
  • 2
    There is no language C/C++, but the two **different** languages C and C++. Pick **one** of them. – too honest for this site Aug 23 '16 at 18:48
  • What does the debugger say? – too honest for this site Aug 23 '16 at 18:49
  • I chose C). I didn't use debugger, it's a shame but I don't know how to use gdb and I don't have an IDE installed right now (it's just a VM with Ubuntu 14.04) – daniel.kish Aug 23 '16 at 18:52
  • 1
    `if (mkfifo ("myfifo", 0600) != 0)` is using an octal value, 384 decimal, if that is relevant. – Weather Vane Aug 23 '16 at 18:52
  • I sincerely admit that don't know what exactly 0600 means but it's supposed to work since everybody I read use that value. And yes I know it's an octal value. – daniel.kish Aug 23 '16 at 18:53
  • You yourself don't understand the code _you_ wrote? – iRove Aug 23 '16 at 18:54
  • @daniel.kish `man 2 umask`. should fill you in on the relevance of that value. – WhozCraig Aug 23 '16 at 18:59
  • That while loop in the reader looks like it would be better as a for loop. That doesn't help your problem, but it makes the code more clear. – Riley Aug 23 '16 at 19:48
  • regarding `0600` this is the permissions for the fifo node. it says `octal`, `owner=read/write`, `group=no permissions`, `world=no permissions` – user3629249 Aug 24 '16 at 21:23
  • in the writer code, this line: `int r = write (fd, msg, len);` is not quite correct. the function: `write()` returns a `ssize_t`, not an `int` – user3629249 Aug 24 '16 at 21:25
  • when the call to `mkfifo()` fails, there is no reason to continue with the code execution after outputting the error message, so the call to `perror()` should be followed by a call to `exit( EXIT_FAILURE );` – user3629249 Aug 24 '16 at 21:27
  • the call to `mkfifo()` will fail, with error code `EEXIST` when the fifo already exists. Strongly suggest 1) check for failure 2) delete the fifo file after all communication is completed – user3629249 Aug 24 '16 at 21:32
  • the reader code is missing the statement: `#include `, so the functions: `read()` and `write()` are not defined – user3629249 Aug 24 '16 at 21:35
  • when this line evaluates to 'true' `if (r == -1)`, then is followed by all call to `perror()`, it needs a following statement: `exit( EXIT_FAILURE );` – user3629249 Aug 24 '16 at 21:39
  • a fifo has no concept of records, it is just a stream of bytes, so the code needs to implement a check that a full record was read, and if not, try to read the rest of the record. And the code needs to call `close(fd);` when done reading the fifo – user3629249 Aug 24 '16 at 21:42
  • for ease of readability and understanding, 1) use meaningful variable names. `r` is NOT a meaningful variable name. 2) separate code blocks (for, if, else, while, do...while, switch, case, default) via a blank line – user3629249 Aug 24 '16 at 21:44
  • when compiling, always enable all the warnings, then fix those warnings. (for `gcc`, at a minimum use: `-Wall -Wextra -pedantic` I also use: `-Wconversion -std=gnu99` ) – user3629249 Aug 24 '16 at 21:46
  • the code contains some 'magic' numbers. 'magic' numbers are numbers with no basis. in this case, 10 and 50. Strongly suggest using an `enum` statement or `#define` statements to give those 'magic' numbers meaningful names, then use those meaningful names throughout the code – user3629249 Aug 24 '16 at 21:48
  • in modern C, when the `main()` function has no 'return 0;` statement at the end, the compiler will automatically cause a return of 0, so no longer necessary to have the `return 0;` statement at the end – user3629249 Aug 24 '16 at 21:51

1 Answers1

1

When the exits (after 10 iterations), the writer receives a SIGPIPE due to the read end being closed. So, the default action for the signal SIGPIPE is executed which to terminate the program. That's why you don't see the final printf() is not executed.

Instead you could ignore (SIG_IGN) the signal SIGPIPE in the writer by calling sigaction() and then handle the write error yourself.

P.P
  • 117,907
  • 20
  • 175
  • 238