c++ - Calling external program using boost::process causes caller to hang (Linux) -


i using boost::process call external program - external program reads input via stdin, , writes stdout , stderr. external program follows (expects single argument - path file debugging)

#include <fstream> #include <iostream> #include <stdexcept> #include <string> #include <vector>  int main(int argc, char** argv) {     try     {         if (argc != 2)         {             throw std::logic_error("expected 2 arguments");         }          std::ofstream ofs(argv[1]);          std::vector<std::string> sometestinput;          ofs << "starting program..." << std::endl;          // read cin         {             ofs << "reading cin..." << std::endl;             std::string input;             while (std::getline(std::cin, input))             {                 ofs << "received cin: " << input << std::endl;                 sometestinput.emplace_back(input);             }              ofs << "finished receiving cin..." << std::endl;         }          // error if nothing has been input         if (sometestinput.empty())         {             throw std::logic_error("expected input , received nothing...");         }          ofs << "writing cout..." << std::endl;          // write cout         (const auto& output : sometestinput)         {             std::cout << output << '\n';         }          ofs << "finished!\n";     }     catch (std::exception& e)     {         std::cerr << "error caught: " << e.what() << '\n';         return 1;     }      return 0; } 

the caller expects 2+ arguments, 1 of path external program, , rest passed on arguments external program.

it hangs while waiting process exit, , seems external program waiting eof stdin.

#include <memory> #include <vector> #include <boost/iostreams/device/file_descriptor.hpp> #include <boost/iostreams/stream.hpp> #include <boost/process.hpp>  int main(int argc, char** argv) {     try     {         if (argc < 2)         {             throw std::logic_error("expecting @ least 2 arguments...");         }          std::vector<std::string> args;          (int = 1; < argc; ++i)         {             args.emplace_back(argv[i]);         }          std::cout << "creating stdout, stderr pipes...\n";          // create pipes stdout, stderr         boost::process::pipe pstdout = boost::process::create_pipe();         boost::process::pipe pstderr = boost::process::create_pipe();          std::cout << "mapping pipes sources...\n";          // map pipe source stdout , stderr sources         boost::iostreams::file_descriptor_source sourcestdout(pstdout.source, boost::iostreams::close_handle);         boost::iostreams::file_descriptor_source sourcestderr(pstderr.source, boost::iostreams::close_handle);          std::cout << "setting streams sources...\n";          // , set streams sources         boost::iostreams::stream<boost::iostreams::file_descriptor_source> istdout(sourcestdout);         boost::iostreams::stream<boost::iostreams::file_descriptor_source> istderr(sourcestderr);          std::unique_ptr<boost::process::child> p;          // want check process result, need ensure stdin handle closed properly,         // place in separate scope         {             std::cout << "mapping pipes sinks...\n";              // map pipe sink stdout , stderr sinks             boost::iostreams::file_descriptor_sink sinkstdout(pstdout.sink, boost::iostreams::close_handle);             boost::iostreams::file_descriptor_sink sinkstderr(pstderr.sink, boost::iostreams::close_handle);              std::cout << "creating stdin pipe, mapping source , sink...\n";              boost::process::pipe pstdin = boost::process::create_pipe();              // stdin, map pipe source , sink before - want close on exiting scope             boost::iostreams::file_descriptor_sink sinkstdin(pstdin.sink, boost::iostreams::close_handle);             boost::iostreams::file_descriptor_source sourcestdin(pstdin.source, boost::iostreams::close_handle);             boost::iostreams::stream<boost::iostreams::file_descriptor_sink> ostdin(sinkstdin);              std::cout << "calling process... \n";              // call process             p = std::unique_ptr<boost::process::child>(new boost::process::child(boost::process::execute(                 boost::process::initializers::set_args(args),                 boost::process::initializers::throw_on_error(),                 boost::process::initializers::bind_stdout(sinkstdout),                 boost::process::initializers::bind_stderr(sinkstderr),                 boost::process::initializers::bind_stdin(sourcestdin)                 )));              std::cout << "sending test data...\n";              // send test data cin - comment out below test error case             ostdin << "test input 1\n";             ostdin << "some\n";             ostdin << "useful\n";             ostdin << "data\n";              std::cout << "test data sent, exiting scope...\n";         }          std::cout << "check if process has exited...\n";          // check if process has exited ok - if not, report errors         if (boost::process::wait_for_exit(*p))         {             std::cout << "has not exited ok, reporting problems...\n";              // gather output stderr             std::string error;             while (std::getline(istderr, error))             {                 std::cout << "error: " << error << '\n';             }              throw std::logic_error("problem executing testprogram...");         }          std::cout << "exited ok, here output callee...\n";          // gather output         std::string output;         while (std::getline(istdout, output))         {             std::cout << output << '\n';         }     }     catch (std::exception& e)     {         std::cerr << "error: " << e.what() << '\n';         return 1;     } } 

i under impression placing stdin pipe , related sources/sinks within scope guarantee they're closed, , therefore send eof.

the same code works under windows (vs2013, boost_1_53).

i using boost_1_53, boost-process 0.5, gcc 4.8.2.

that not happen, because there's still pipe handle open in child process; closed on posix if set explicitly (on windows done automatically). you'd need add that:

#if defined (boost_posix_api) fcntl(pstdout.sink, f_setfd, fd_cloexec); fcntl(pstderr.sink, f_setfd, fd_cloexec); #endif 

i recommend use boost.asio , wait asynchronously exit of subprocess , close pipes there.

just fyi: i've worked on boost-process 0.6 has different interface makes asio stuff easier. in review in october/november, might become official boost library soon. it's in beta might want check 1 out.


Comments

Popular posts from this blog

java - Suppress Jboss version details from HTTP error response -

gridview - Yii2 DataPorivider $totalSum for a column -

Sass watch command compiles .scss files before full sftp upload -