Boost.Process
repository·develop·Indexed 40 days ago
https://github.com/boostorg/processA C++11 library providing a high-level interface for managing system processes, their lifecycles, and inter-process communication. It includes tools for spawning processes via process launchers, manipulating environment variables, and managing exit codes and signals. Supports Boost version 1.64 or later and provides specialized launchers for Windows and POSIX platforms.
What's inside Boost.Process
- Boost.Process is a C++11 library designed for the comfortable management of processes. It provides an interface for spawning processes, managing their lifecycles, and handling inter-process communication.
Use Boost.Process V2 for process management
developBoost.Process V2 is the current default version, redesigned for simplicity and reliability. Unlike V1, which used a DSL-like constructor for partial settings, V2 uses a simplified interface where each argument addresses a single logical component (e.g.,
process_stdiofor I/O orprocess_environmentfor environment variables).Key improvements in V2 include:
- Full Asio Integration: Uses Asio pipes and file handles for subprocesses to prevent deadlocks.
- Reliable Waiting: Uses
pidfd_openon Linux andHANDLEs on Windows to implement waiting via Asio's async/cancellation model, replacing the unreliable signal-basedwait_forfrom V1. - UTF-8 Support: Assumes UTF-8 everywhere, utilizing UTF-16 APIs on Windows.
- FD Safety: Automatically closes all non-whitelisted file descriptors on POSIX systems by default.
- Explicit Configuration: Every process requires a path and arguments, avoiding the mixture of command-style and exe-args found in V1.
extern std::unordered_map<std::string, std::string> my_env; extern asio::io_context ctx; // V2 uses explicit component initializers process proc(ctx, "./test", {"--help"}, process_stdio{nullptr, {}, {}}, process_environment(my_env));Query and manipulate the process environment
developThe
boost::process::environmentnamespace provides tools to interact with the current process's environment variables.Key behaviors to note:
- Case Sensitivity: Environment variable names are case-insensitive on Windows. The
key_traitsclass handles this platform-specific behavior automatically. - Path Lists: Environment variables containing lists (like
PATH) are often separated by:or;. You can useenvironment::valueandenvironment::value_viewto iterate through these individual values. - Data Formats: An environment can be represented as a list of strings or a list of string-pairs. While flexible, it is recommended to use the provided
environmenttypes to ensure correct value comparisons.
- Case Sensitivity: Environment variable names are case-insensitive on Windows. The
Understand the `basic_process_handle` abstraction
developA
basic_process_handleis an unmanaged version of a process. Unlike managed process objects, abasic_process_handledoes not automatically terminate the process when it is destroyed, nor does it automatically keep track of the exit code.Key behaviors to note:
- Lifecycle: Destruction does not end the process.
- Exit Code Discovery: The exit code might be discovered early during a call to
running(). It can only be discovered if the process has already exited. - Platform Differences: On non-Linux POSIX systems, obtaining a file descriptor for a PID might not be possible, meaning the handle may rely on signals instead.
How process cancellation works in `async_execute`
developWhen cancelling an asynchronous execution started via
async_execute, the library signals the child process to exit. The method of exit depends on thecancellation_typeused. The library selects the lowest (most conservative) cancellation type requested. Note that subprocesses may ignore signals that are notterminal./* Cancellation type mappings: */ // cancellation_type::total -> interrupt // cancellation_type::partial -> request_exit // cancellation_type::terminal -> terminateUse `cstring_ref` for null-terminated string views
developThecstring_reftype acts as a string-view-like object specifically designed to hold a pointer to a null-terminated C-style string. It provides a way to work with C-strings while offering a more modern interface similar tostd::string_view.Access the current process environment as a range
developYou can iterate over the current process's environment variables using
environment::current(). This returns acurrent_view, which acts as a range ofkey_value_pair_viewobjects.Warning: Accessing the environment in this way is not thread-safe.
Usage Pattern
You can use structured bindings to iterate through the environment easily:
void dump_my_env(environment::current_view env = environment::current()) { for (auto & [k, v] : env) std::cout << k.string() << " = " << v.string() << std::endl; }Manage process lifetime and exit codes
developLifetime Management
- Automatic Termination: If the process handle goes out of scope, the subprocess is terminated.
- Detaching: To prevent automatic termination when the handle is destroyed, call
proc.detach(). Warning: Detaching can lead to zombie processes.
Monitoring and Exit Codes
- Status: Use
.running()to check if the process is still active. - Exit Code: Once a process has completed, you can retrieve the exit code using
.exit_codeor by capturing the return value of.wait(). - Native Exit Code: On POSIX systems,
.native_exit_codeprovides additional platform-specific information beyond the standard return value frommain.
Use pipes for subprocess I/O
developYou can use Boost.Asio pipes for I/O with a subprocess. When using them within
process_stdio, the pipes are automatically connected: one end is assigned to the child process, and the other end is available to the parent process.- Use
readable_pipeforout(stdout) anderr(stderr). - Use
writable_pipeforin(stdin).
// Example of using pipes for I/O boost::asio::ip::tcp::socket socket(io_context); // ... (setup pipes) ... // Assigning pipes to process_stdio // readable pipes -> out/err, writable pipes -> in- Use
Install and use Boost.Process
developBoost.Process requires Boost version 1.64 or later. Ensure your environment has the Boost libraries installed and configured before attempting to use Boost.Process.Set the environment for a child process with `process_environment`
developTo provide a specific environment to a new child process (instead of inheriting the current process's environment), use the
process_environmentclass. This class can be initialized with strings in the format"KEY=VALUE".Usage
Pass an instance of
process_environmentto theprocessconstructor.// Setting a single variable process proc{executor, find_executable("printenv"), {"foo"}, process_environment{"foo=bar"}}; // Reusing an environment object for multiple processes auto exe = find_executable("printenv"); process_environment env = {"FOO=BAR", "BAR=FOO"}; process proc1(executor, exe, {"FOO"}, env); process proc2(executor, exe, {"BAR"}, env);Note: The
process_environmentinitializer persists its state and can be reused, but be aware that the Operating System is allowed to modify its internal state.process proc{executor, find_executable("printenv"), {"foo"}, process_environment{"foo=bar"}};Redirect streams to the null device using `nullptr`
developTo ignore a specific stream's output or to provide only an EOF (End Of File) as input to a subprocess, assign
nullptrto the corresponding stream. This automatically redirects the stream to the system's null device (/dev/nullon POSIX orNULon Windows).// Example of redirecting to null // include::../example/stdio.cpp[tag=null]