pp
, you quickly discover a
problem (as indeed we did with our in-class demo): the coin
toss program can't continue because the pp plotting function
never returns. So the whole concept of a loop in which we can
ask for more and more trials is out the window.
This led us to an approach in which, instead of calling the pp
library function we used (due to Addison's vision) the system
function like this:
system("pp &");to spawn a pp-process and bring control immediately back to our coin toss program. The only problem here is that we have no mechanism for sending pp the points we want plotted. We could create a file
tmpfile
, write the points to
tmpfile
and then invoke pp with:
system("pp < tmpfile &");This approach is ugly, however, in a few ways. First of all, writing data to disk is very slow, so you're introducing a completely unnecessary and very serious bottleneck into the system. Second, you have this file sitting around and, unfortunately, it's very difficult to tell whether and when it can be removed, and whose job it would be to do the removing.
Named pipes (or FIFOS) offer us a better alternative. What you create is something that looks like a file, and in many ways acts like a file, but which never actually involves storing the data you write in the filesystem. It's like a chat room - an address that the writer and reader agree to meet at to exchange data. Data isn't stored, even temporarily, in a FIFO. It's just the connection between reader and writer. This makes it fast, and this also means it enforces a bit of necessary synchronization: the writer has to wait to write until there's someone there to read, and the reader sits there and waits until there's something there to be read. Now our setup is like this:
1) create FIFO f 2) system(pp < f &); 3) write points to f 4) remove fSome salient points: 1) we can't actually start part 3 until the pp process is spawned and connected to pipe f. Why? Because you can't write without someone reading on the other end! 2) you can remove a FIFO with
rm
, but this only
disassociates the name from the actual pipe. The pipe lives
on until nobody has it open any more.
3) We can safely rm
the FIFO at step 4
even if the pp-process still had some data left to read,
because the pipe wouldn't die, just its name would, and since
pp has opened the pipe already its name isn't needed.
In actual code these steps look like this:
// make a named pipe in /tmp string fifoname = "/tmp/cthPipe"; mkfifo( fifoname.c_str() , S_IRUSR | S_IWUSR); // use the Addison trick to spawn a pp process and // return control back to our program immediately // NOTE: this requires that pp is in the current directory system(("pp < " + fifoname + " &").c_str()); // open ofstream to the pipe, write to it, close it ofstream fout(fifoname.c_str()); for(int i = 0; i < X.size(); ++i) fout << X[i] << ' ' << Y[i] << endl; fout.close(); // remove the named pipe. Note: the pipe gets removed // as an entry in the filesystem, but lives on namelss // as long as the pp-process which refernces it is around system(("/usr/bin/rm " + fifoname).c_str());
system
spawns.