2016-07-19 10 views
0

私はboost :: processを使って外部プログラムを呼び出しています - 外部プログラムはstdin経由で入力を読み込み、stdoutとstderrに書き込みます。 (単一の引数を期待 - デバッグ用のファイルへのパス)、以下のように外部プログラムがあるboost :: processを使って外部プログラムを呼び出すと、呼び出し側がハングする(Linux)

#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 two arguments"); 
     } 

     std::ofstream ofs(argv[1]); 

     std::vector<std::string> someTestInput; 

     ofs << "Starting program..." << std::endl; 

     // Read from cin 
     { 
      ofs << "Reading from cin..." << std::endl; 
      std::string input; 
      while (std::getline(std::cin, input)) 
      { 
       ofs << "Received from cin: " << input << std::endl; 
       someTestInput.emplace_back(input); 
      } 

      ofs << "Finished receiving from cin..." << std::endl; 
     } 

     // Error if nothing has been input 
     if (someTestInput.empty()) 
     { 
      throw std::logic_error("Expected some input and received nothing..."); 
     } 

     ofs << "Writing to cout..." << std::endl; 

     // Write to cout 
     for (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; 
} 

は、呼び出し側が外部プログラムへのパスであるそのうちの一つ2+引数を期待するが、残りは渡され外部プログラムの引数として使用します。

プロセスが終了するのを待っている間にハングし、外部プログラムが標準からのEOFを待っているようです。

#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 at least 2 arguments..."); 
     } 

     std::vector<std::string> args; 

     for (int i = 1; i < argc; ++i) 
     { 
      args.emplace_back(argv[i]); 
     } 

     std::cout << "Creating stdout, stderr pipes...\n"; 

     // Create pipes for stdout, stderr 
     boost::process::pipe pstdout = boost::process::create_pipe(); 
     boost::process::pipe pstderr = boost::process::create_pipe(); 

     std::cout << "Mapping pipes to sources...\n"; 

     // Map pipe source from stdout and stderr to 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 up streams for the sources...\n"; 

     // And set up streams for the 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 to check for process result, but also need to ensure stdin handle is closed properly, 
     // so place everything in separate scope 
     { 
      std::cout << "Mapping pipes to sinks...\n"; 

      // Map pipe sink from stdout and stderr to 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 to source and sink...\n"; 

      boost::process::pipe pstdin = boost::process::create_pipe(); 

      // For stdin, map pipe to source and sink as before - want it to close on exiting this 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 some test data to cin - comment out the below to test for 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 from 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 is output from the callee...\n"; 

     // Gather the 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; 
    } 
} 

私は私の範囲内で標準入力パイプと関連するソース/シンクを配置すること、それらが閉じている保証するため、EOFを送信するという印象の下にありました。

同じコードはWindows(VS2013、boost_1_53)で完全に動作します。

私はboost_1_53、boost-process 0.5、gcc 4.8.2を使用しています。

答えて

1

子プロセスでまだパイプハンドルが開いているので、これは起こりません。それは明示的に(ウィンドウ上では自動的に行われる)それを設定するとposixでのみ閉じられます。ですから、そのような何かを追加する必要があるだろう:

#if defined (BOOST_POSIX_API) 
fcntl(pstdout.sink, F_SETFD, FD_CLOEXEC); 
fcntl(pstderr.sink, F_SETFD, FD_CLOEXEC); 
#endif 

私はしかしboost.asioを使用して、サブプロセスの終了のための非同期待ち、そこにパイプを閉じることをお勧めします。

ちょうどFYI:私は別のインターフェイスを持っていますが、asioの作業をはるかに簡単にするboost-process 0.6について取り組んできました。これは10月/ 11月に検討される予定ですので、まもなく正式なブックス図書館になるかもしれません。現在ベータ版になっているので、それをチェックしたいかもしれません。

+0

素晴らしいです、ありがとうございました - 問題をうまく解決しました。私は実際にboost :: asioをexporedしていませんが、私はちょうどプロセスライブラリを通して自分の道を探しています。私は調査します! – DaveM

関連する問題