neutrino
neutrino

Reputation: 31

Fork, pipe and file operations

I have got a pipe to enable communication between 2 processes in forked program. It was created with pipe() call - http://linux.die.net/man/2/pipe . Everything goes right until I want to perform some file operations.

This code works:

pipe.writeBuffer(message.c_str(), message.length());
ofstream file;
file.open(name.c_str(), ios::app);
file << "stringData";    // put some data to file (many times)

But this one not:

ofstream file;
file.open(name.c_str(), ios::app);
pipe.writeBuffer(message.c_str(), message.length());
file << "stringData";    // put some data to file (many times)

In the second example there is no effect of "file << someStream" - I get the empty file. What is wrong with that? Is it a problem with file descriptor? Pipe uses fd[0] - input and fd[1] - output. Maybe fstream uses also the same output file handler?

Here is the "working" sample: http://pastebin.com/gJ4PbHvy

#include <sys/types.h>
#include <cstdlib>
#include <unistd.h>
#include <iostream>
#include <fstream>

#define maxSize 64

using namespace std;

class Pipe
{
    public:
        Pipe()
        {
            pipe(fdesc);
        }

        ~Pipe() {}

        void writeBuffer(const char* message, size_t length)
        {
            close(fdesc[0]);
            write(fdesc[1], message, length);

        }

        void readBuffer()
        {
            char buffer[maxSize];
            close(fdesc[1]);
            size_t result = read(fdesc[0], &buffer, sizeof(buffer));
            cout << buffer << endl;

        }

    private:
        int fdesc[2];

};

class Writer
{
    public:
        Writer(Pipe &obj)
        {
            pipe = obj;
        }

        ~Writer()
        {}

        void entry()
        {
            std::string name = "./myFile";
            ofstream file;
            file.open(name.c_str(), ios::app);

            std::string message = "hello world";
            pipe.writeBuffer(message.c_str(), message.length()+1);

            if (file.is_open())
            {
                file << "Hello World!" << endl;
                file.close();
            }
            else
            {
                perror("file.is_open()");
            }

            sleep(1);

        }

    private:
        Pipe pipe;

};


class Reader
{
    public:
        Reader(Pipe &obj)
        {
            pipe = obj;
        }

        ~Reader()
        {}


        void entry()
        {
            pipe.readBuffer();
            sleep(1);

        }

     private:
        Pipe pipe;

};

int main(int argc, char *argv[])
{
    Pipe pipe;
    Reader reader(pipe);
    Writer writer(pipe);

    pid_t pid = fork();

    if (pid == -1) 
    {
        perror("fork");
        exit(EXIT_FAILURE);
    }

    if (pid == 0) 
    {    
        // child process
        while(1)
            reader.entry();

    } 
    else 
    {
        // parent process
        while(1)
            writer.entry();

    }

}

Upvotes: 1

Views: 979

Answers (1)

Armali
Armali

Reputation: 19395

With the posted program, the described issue of getting an empty file isn't reproducible, since on each run it does write one line Hello World! into myFile, but this still shows the error, because you intend to write one line every second. The reason is the close(fdesc[0]) in writeBuffer(): While it is correct to close the read end of the pipe once in the writer process, it is incorrect to do it every time writeBuffer() is called, as that file descriptor can (and in the case at hand, does) have been reused after the first close() for another file (here the file ofstream file), which is after it closed instead of the (already closed) pipe, so that nothing can be written into the file. Fix: Arrange your program to close the pipe end only once, e. g. by changing

            close(fdesc[0]);

to

            if (0 <= fdesc[0]) close(fdesc[0]), fdesc[0] = -1;

Upvotes: 1

Related Questions