0

I have two programs to write and read a FIFO. One is read(O_RDONLY) a FIFO. Another is write data into this FIFO. This is code:

Read: The executable file is named read.

#include<errno.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<stdio.h>
#include<string.h>

int main(int argc, char *argv[])
{
    int fd, nread;
    const char *pipe_file = "/tmp/test_fifo";

    char buf[0x100] ;

    fd = open(pipe_file, O_RDONLY);

    while(1) {
        printf("\n"); /*  */
        memset(buf, 0, 100);
        nread = read(fd, buf, 0x100);
        printf("data is %s", buf);
        sleep(1);
    }

    return 0;
}

Write: The executable file is named write.

#include<errno.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<stdio.h>
#include<string.h>

int main(int argc, char *argv[])
{
    int fd;
    int num = 1234;
    char *s = "changzhi";
    const char *pipe_file = "/tmp/test_fifo";


    fd = open(pipe_file, O_WRONLY);
    write(fd, s, strlen(s));

    return 0;
}

The FIFO named /tmp/test_fifo is already exists. When I run read to read FIFO and run write to write the FIFO, everything goes ok. But, the read can not read data when there is no printf("\n"); in read code. I don not know why. Could someone help me ? Thanks a lot!

changzhi
  • 2,641
  • 9
  • 36
  • 46
  • Note that there are system-provided commands called `read` and `write`. Are you sure you aren't accidentally using one of those? (You will be OK if you use `./read` and `./write`, for example.) In your code, you don't check that your open succeeds; you don't report that your open succeeded; you don't check that your read or write operations succeed; you don't report when the write has succeeded. You need to run the programs in parallel: `./read & ./write` or `./write & ./read`. – Jonathan Leffler May 12 '14 at 06:18

2 Answers2

2

Your second printf() is buffered until the \n is written. The read is not blocked :-)

Rewrite your loop:

while(1) {
    memset(buf, 0, 100);
    nread = read(fd, buf, 0x100);
    printf("data is %s\n", buf);
    sleep(1);
}
cadrian
  • 7,332
  • 2
  • 33
  • 42
  • 1
    Without the newline in the `data is` call to `printf()`, the loop goes back to the top and then does `printf("\n")` after the 1 second delay caused by `sleep(1)`. But you're correct that doing things that way is … aconventional, shall we say? – Jonathan Leffler May 12 '14 at 06:39
  • Could you explain the details of `buffer and blocked`? Thanks a lot! – changzhi May 12 '14 at 07:04
  • The output is line-buffered by default; the output from `printf()` won't appear until there is a newline, and then the data up to the newline appears. Anything after the newline waits until a newline appears. Your second `printf()`, therefore, doesn't force the data out. However, after a 1 second sleep, the loop goes back to the top and the `printf("\n");` forces out the '`data is …`' material. In the original code, the loop is infinite until you interrupt the program because you don't test for EOF or read errors. – Jonathan Leffler May 12 '14 at 07:09
  • For 'blocked', the `read()` won't return until either there is some data in the FIFO to return, or until there is no writer with the FIFO open, whereupon the `read()` returns with an EOF (0 bytes read). Your code ignores this return code, so the loop continues indefinitely. The `open()` also blocks; in each program, it will not complete until there is another (the other) process also with the FIFO open. – Jonathan Leffler May 12 '14 at 07:10
0

With cleanly compiling code under stringent compilation options:

$ gcc -O3 -g -std=c11 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes \
>     -Wold-style-definition -Werror write.c -o write
$ gcc -O3 -g -std=c11 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes \
>     -Wold-style-definition -Werror read.c -o read
$

the code basically works for me. I've added error checking. The slightly odd argv[argc-argc] prints argv[0] but avoids a warning (error because of -Werror) about argc being unused.

read.c

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

int main(int argc, char **argv)
{
    int fd, nread;
    const char *pipe_file = "/tmp/test_fifo";

    char buf[0x100];

    if ((fd = open(pipe_file, O_RDONLY)) < 0)
    {
        fprintf(stderr, "%s: Failed to open FIFO %s\n", argv[argc-argc], pipe_file);
        return 1;
    }
    printf("%s: open successful\n", argv[0]);

    while(1) {
        printf("\n"); /*  */
        memset(buf, 0, 100);
        nread = read(fd, buf, 0x100-1);
        if (nread <= 0)
            break;
        printf("data is %s\n", buf);
        sleep(1);
    }

    return 0;
}

write.c

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

int main(int argc, char *argv[])
{
    int fd;
    char *s = "changzhi";
    const char *pipe_file = "/tmp/test_fifo";

    if ((fd = open(pipe_file, O_WRONLY)) < 0)
    {
        fprintf(stderr, "%s: failed to open FIFO %s\n", argv[argc-argc], pipe_file);
        return 1;
    }
    printf("%s: open successful\n", argv[0]);
    if (write(fd, s, strlen(s)) <= 0)
    {
        fprintf(stderr, "%s: failed to open FIFO %s\n", argv[argc-argc], pipe_file);
        return 1;
    }
    printf("%s: write successful\n", argv[0]);

    return 0;
}

Sample output

$ ./read & ./write
[1] 85542
./write: open successful
./write: write successful
./read: open successful

data is changzhi
$ 

[1]+  Done                    ./read
$ ./write & ./read
[1] 85544
./write: open successful
./read: open successful

./write: write successful
data is changzhi

[1]+  Done                    ./write
$

The programs report an error sensibly if the FIFO does not exist.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • Thank you for your answer. But I still have some problem about code. It can not work, when I comment the `printf("\n");` in read program. Is there something wrong about buffer caused the read operation is blocked? You can see @cadrian answer. – changzhi May 12 '14 at 07:01
  • When I remove the `printf("\n");` line from `read.c`, the program works fine — it simply prints one fewer newlines (which is arguably an improvement). Have you copied the code verbatim, or did you try to retrofit my changes into your code? Which platform are you working on? I'm testing on Mac OS X 10.9.2 Mavericks with GCC 4.9.0, though I would expect the code to work fine with any POSIX-ish platform from the current millennium with any C compiler (though you'd need to tweak the compilation flags for non-GCC compilers, of course, or really old versions of GCC). – Jonathan Leffler May 12 '14 at 07:05
  • I'm testing on CentOS 6.4, and gcc version is 4.4.7 20120313 (Red Hat 4.4.7-4) (GCC). – changzhi May 13 '14 at 01:30
  • Well, I'd certainly not expect any trouble with CentOS 6.4 and GCC 4.4.7. Did you copy the code from my answer verbatim? Did you compile with the options I showed? I check compiled on Ubuntu 14.04 with GCC 4.8.2, and it performed fine — with and without the `printf("\n");` line. – Jonathan Leffler May 13 '14 at 02:31