background.cpp 2.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. #include <future>
  2. #include <iostream>
  3. #include <mutex>
  4. #include <string>
  5. #include <reproc++/drain.hpp>
  6. #include <reproc++/reproc.hpp>
  7. static int fail(std::error_code ec)
  8. {
  9. std::cerr << ec.message();
  10. return ec.value();
  11. }
  12. // The background example reads the output of a child process in a background
  13. // thread and shows how to access the current output in the main thread while
  14. // the background thread is still running.
  15. // Like the forward example it forwards its arguments to a child process and
  16. // prints the child process output on stdout.
  17. int main(int argc, const char **argv)
  18. {
  19. if (argc <= 1) {
  20. std::cerr << "No arguments provided. Example usage: "
  21. << "./background cmake --help";
  22. return EXIT_FAILURE;
  23. }
  24. reproc::process process;
  25. reproc::stop_actions stop = {
  26. { reproc::stop::terminate, reproc::milliseconds(5000) },
  27. { reproc::stop::kill, reproc::milliseconds(2000) },
  28. {}
  29. };
  30. reproc::options options;
  31. options.stop = stop;
  32. std::error_code ec = process.start(argv + 1, options);
  33. if (ec == std::errc::no_such_file_or_directory) {
  34. std::cerr << "Program not found. Make sure it's available from the PATH.";
  35. return ec.value();
  36. } else if (ec) {
  37. return fail(ec);
  38. }
  39. // We need a mutex along with `output` to prevent the main thread and
  40. // background thread from modifying `output` at the same time (`std::string`
  41. // is not thread safe).
  42. std::string output;
  43. std::mutex mutex;
  44. auto drain_async = std::async(std::launch::async, [&process, &output,
  45. &mutex]() {
  46. // `sink::thread_safe::string` locks a given mutex before appending to the
  47. // given string, allowing working with the string across multiple threads if
  48. // the mutex is locked in the other threads as well.
  49. reproc::sink::thread_safe::string sink(output, mutex);
  50. return reproc::drain(process, sink, sink);
  51. });
  52. // Show new output every 2 seconds.
  53. while (drain_async.wait_for(std::chrono::seconds(2)) !=
  54. std::future_status::ready) {
  55. std::lock_guard<std::mutex> lock(mutex);
  56. std::cout << output;
  57. // Clear output that's already been flushed to `std::cout`.
  58. output.clear();
  59. }
  60. // Flush any remaining output of `process`.
  61. std::cout << output;
  62. // Check if any errors occurred in the background thread.
  63. ec = drain_async.get();
  64. if (ec) {
  65. return fail(ec);
  66. }
  67. int status = 0;
  68. std::tie(status, ec) = process.stop(options.stop);
  69. if (ec) {
  70. return fail(ec);
  71. }
  72. return status;
  73. }