我正在通过boost::process
. 该过程使用std::cout
和std::cerr
来输出一些信息。我需要检索这些信息。在某些时候,我希望能够存储那些保留顺序和严重性的输出(来自cout
or的输出cerr
)。
boost::process
但考虑到重定向输出的方式,我无法做到这一点。我只能重定向std::cout
到一个特定的 ipstream 和std::cerr
另一个。然后,在阅读它们时,我无法保留顺序。
这是一个 MCVE 隔离问题:
#include <iostream>
#include <boost/process.hpp>
#include <boost/thread.hpp>
#include <boost/bind.hpp>
void doReadOutput( boost::process::ipstream* is, boost::process::ipstream* err, std::ostream* out )
{
std::string line;
if ( std::getline( *is, line ) )
*out << "cout: " << line << std::endl;
if ( std::getline( *err, line ) )
*out << "cerr: " << line << std::endl;
}
void readOutput( boost::process::ipstream* is, boost::process::ipstream* err, std::ostream* out, std::atomic_bool* continueFlag )
{
std::string line;
while ( *continueFlag )
{
doReadOutput( is, err, out );
}
// get last outputs that may remain in buffers
doReadOutput( is, err, out );
}
int main( int argc, char* argv[] )
{
if ( argc == 1 )
{
// run this same program with "foo" as parameter, to enter "else" statement below from a different process
try
{
boost::process::ipstream is_stream, err_stream;
std::stringstream merged_output;
std::atomic_bool continueFlag = true;
boost::process::child child( argv[0],
std::vector<std::string>{ "foo" },
boost::process::std_out > is_stream,
boost::process::std_err > err_stream );
boost::thread thrd( boost::bind( readOutput, &is_stream, &err_stream, &merged_output, &continueFlag ) );
child.wait();
continueFlag = false;
thrd.join();
std::cout << "Program output was:" << std::endl;
std::cout << merged_output.str();
}
catch ( const boost::process::process_error& err )
{
std::cerr << "Error: " << err.code() << std::endl;
}
catch (...) // @NOCOVERAGE
{
std::cerr << "Unknown error" << std::endl;
}
}
else
{
// program invoked through boost::process by "if" statement above
std::cerr << "Error1" << std::endl;
std::cout << "Hello World1" << std::endl;
std::cerr << "Error2" << std::endl;
std::cerr << "Error3" << std::endl;
std::cerr << "Error4" << std::endl;
std::cerr << "Error5" << std::endl;
std::cout << "Hello World2" << std::endl;
std::cerr << "Error6" << std::endl;
std::cout << "Hello World3" << std::endl;
}
return 0;
}
当我执行这个程序(在 Windows 10 下使用 Visual Studio 2019 编译)时,它输出:
Program output was:
cout: Hello World1
cerr: Error1
cout: Hello World2
cerr: Error2
cout: Hello World3
cerr: Error3
cerr: Error4
cerr: Error5
cerr: Error6
虽然我想要:
Program output was:
cerr: Error1
cout: Hello World1
cerr: Error2
cerr: Error3
cerr: Error4
cerr: Error5
cout: Hello World2
cerr: Error6
cout: Hello World3
有没有办法做到这一点?
编辑,正如一些程序员花花公子所建议的那样,为每个输出流创建了一个线程:
#include <iostream>
#include <boost/process.hpp>
#include <boost/thread.hpp>
#include <boost/bind.hpp>
#include <boost/thread/mutex.hpp>
void doReadOutput( boost::process::ipstream* str, std::ostream* out, const std::string& prefix, boost::mutex* mutex )
{
std::string line;
if ( std::getline( *str, line ) )
{
boost::mutex::scoped_lock lock( *mutex );
*out << prefix << ": " << line << std::endl;
}
}
void readOutput( boost::process::ipstream* str, std::ostream* out, std::string prefix, boost::mutex* mutex, std::atomic_bool* continueFlag )
{
while ( *continueFlag )
{
doReadOutput( str, out, prefix, mutex );
boost::thread::yield();
}
// get last outputs that may remain in buffers
doReadOutput( str, out, prefix, mutex );
}
int main( int argc, char* argv[] )
{
if ( argc == 1 )
{
// run this same program with "foo" as parameter, to enter "else" statement below from a different process
try
{
boost::process::ipstream is_stream, err_stream;
std::stringstream merged_output;
std::atomic_bool continueFlag = true;
boost::process::child child( argv[0],
std::vector<std::string>{ "foo" },
boost::process::std_out > is_stream,
boost::process::std_err > err_stream );
boost::mutex mutex;
boost::thread thrdis( boost::bind( readOutput, &is_stream, &merged_output, "cout", &mutex, &continueFlag ) );
boost::thread thrderr( boost::bind( readOutput, &err_stream, &merged_output, "cerr", &mutex, &continueFlag ) );
child.wait();
continueFlag = false;
thrdis.join();
thrderr.join();
std::cout << "Program output was:" << std::endl;
std::cout << merged_output.str();
}
catch ( const boost::process::process_error& err )
{
std::cerr << "Error: " << err.code() << std::endl;
}
catch (...) // @NOCOVERAGE
{
std::cerr << "Unknown error" << std::endl;
}
}
else
{
// program invoked through boost::process by "if" statement above
std::cerr << "Error1" << std::endl;
std::cout << "Hello World1" << std::endl;
std::cerr << "Error2" << std::endl;
std::cerr << "Error3" << std::endl;
std::cerr << "Error4" << std::endl;
std::cerr << "Error5" << std::endl;
std::cout << "Hello World2" << std::endl;
std::cerr << "Error6" << std::endl;
std::cout << "Hello World3" << std::endl;
}
return 0;
}
然后输出是:
Program output was:
cerr: Error1
cout: Hello World1
cerr: Error2
cout: Hello World2
cerr: Error3
cout: Hello World3
cerr: Error4
cerr: Error5
cerr: Error6
还是出乎意料...