It would be good to provide a set of examples, including at least how to switch between (non-blocking) reads of stdout and stderr from a long-running child process.
int main()
{
redi::ipstream seq("i=0; while [ $i -lt 5 ]; do echo $i;
i=$((i+1)); sleep 1; done; exec >&-; sleep 5");
int i;
while (seq >> i)
std::cout << i << std::endl;
std::cout << "Child finished writing\n";
}
That example shows two things:
As soon as there is input available the stream will read it and return
(it won't block until its internal buffer is full). That gives you
immediate responsiveness when reading data. (It does block while there
are no bytes to be read though.)
The child process closes its stdout file descriptor before it exits,
which causes the pstream to get EOF immediately, even though the child
doesn't exit (and so the pstream can't be destroyed) for another five
seconds.
This modified example uses readsome() for non-blocking reads and
exited() to detect EOF:
#include "pstream.h"
#include <iostream>
using namespace redi;
int main()
{
{
redi::ipstream seq("i=0; while [ $i -lt 5 ]; do echo $i;
i=$((i+1)); sleep 1; done; exec >&-; sleep 5");
unsigned i=0;
char buf[64];
while (seq)
{
if (long nbytes = seq.readsome(buf, sizeof(buf)))
std::cout.write(buf, nbytes).flush();
else if (seq.rdbuf()->exited())
(void) seq.get(); // sets eofbit
else if ((++i % 50000) == 0)
std::cerr << "No output\n";
}
std::cout << "Child finished writing" << std::endl;
}
std::cout << "Child Exited" << std::endl;
}
This will print "No output" to show it's polling and not blocking
while there is no data.
Without the check for exited() it would loop forever, because
readsome() doesn't set eofbit, but when we know the child has exited
we can do a blocking read just to cause the eofbit to be set, so the
loop terminates.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
#include "pstream.h"
#include <iostream>
using namespace redi;
int main()
{
redi::ipstream seq("i=0; while [ $i -lt 5 ]; do echo $i;
i=$((i+1)); sleep 1; done; exec >&-; sleep 5");
int i;
while (seq >> i)
std::cout << i << std::endl;
std::cout << "Child finished writing\n";
}
That example shows two things:
As soon as there is input available the stream will read it and return
(it won't block until its internal buffer is full). That gives you
immediate responsiveness when reading data. (It does block while there
are no bytes to be read though.)
The child process closes its stdout file descriptor before it exits,
which causes the pstream to get EOF immediately, even though the child
doesn't exit (and so the pstream can't be destroyed) for another five
seconds.
This modified example uses readsome() for non-blocking reads and
exited() to detect EOF:
#include "pstream.h"
#include <iostream>
using namespace redi;
int main()
{
{
redi::ipstream seq("i=0; while [ $i -lt 5 ]; do echo $i;
i=$((i+1)); sleep 1; done; exec >&-; sleep 5");
unsigned i=0;
char buf[64];
while (seq)
{
if (long nbytes = seq.readsome(buf, sizeof(buf)))
std::cout.write(buf, nbytes).flush();
else if (seq.rdbuf()->exited())
(void) seq.get(); // sets eofbit
else if ((++i % 50000) == 0)
std::cerr << "No output\n";
}
std::cout << "Child finished writing" << std::endl;
}
std::cout << "Child Exited" << std::endl;
}
This will print "No output" to show it's polling and not blocking
while there is no data.
Without the check for exited() it would loop forever, because
readsome() doesn't set eofbit, but when we know the child has exited
we can do a blocking read just to cause the eofbit to be set, so the
loop terminates.