Boost.Process provides a flexible framework for the C++ programming language to manage running programs, also known as processes. It empowers C++ developers to do what Java developers can do with java.lang.Runtime/java.lang.Process and .NET developers can do with System.Diagnostics.Process. Among other functionality, this includes the ability to manage the execution context of the currently running process, the ability to spawn new child processes, and a way to communicate with them them using standard C++ streams and asynchronous I/O.
The library is designed in a way to transparently abstract all process management details to the user, allowing for painless development of cross-platform applications. However, as such abstractions often restrict what the developer can do, the framework allows direct access to operating system specific functionality - obviously losing the portability features of the library.
This section contains a summary of the most important features provided by the library.
Boost.Process' long-term goal is to provide a portable abstraction layer over the operating system that allows the programmer to manage any running process, not only those spawned by it. Due to the complexity in offering such an interface, the library currently focuses on child process management alone.
As an exception, it also allows access to the caller's process because this is easy to expose, helps in providing a more modular interface and is a very useful feature.
Boost.Process' most important feature is the ability to painlessly launch external applications, control them during their lifetime and set up communication channels between them and their parent. Traditionally, this has been a boring and hard task in C and C++ because there are many details to take into account: create the new process, launch the external binary, set up anonymous pipes to communicate with it, wait for its termination, inspect its exit status, etc.
To make things worse, each major operating system has its own process model and API to manage child processes. Writing an application that deals with both is time consuming and in most cases drives away the developer from his original goal - not related at all to interacting with the underlying operating system. Therefore, Boost.Process provides an abstraction to handle all these details on behalf of the developer.
An application launching a child process typically wants to communicate with it by means of data transfers. This Inter-Process Communication (IPC) happens at the level of file handles and typically involves the standard input (stdin), the standard output (stdout) and the standard error output (stderr). If the operating system supports it (e.g. Unix), other unnamed data streams can be redirected.
In order to properly integrate with the C++ standard library, this IPC is morphed into standard C++ streams making interaction with child processes a piece of cake. Each of these streams can be configured based on many predefined modes, which allow you to simply ignore a stream, collect it for further processing or redirect it to another stream (be it a program, a file or a low-level file handle).
Boost.Process allows a process to be managed in several different operation modes; these are described below:
Asynchronous operation: The child process is spawned and the parent process continues execution. This is the most common operation mode because the parent will typically need to manage the data generated by its child as soon as it is available. At any point, the parent process can decide to synchronize with its child, effectively waiting for its termination.
Synchronous operation: In this scenario, the parent process blocks until its newly spawned children finishes execution. This can be useful in those cases where the parent does not directly receive data generated from its child (e.g. because it is redirected to a file on disk).
Disconnected operation: The parent process forgets about the existence of its child process, which can continue to exist even when the parent dies.
A pipeline is a unidimensional and unidirectional chain of interconnected processes in which the output of one of them is connected to the input of the following. The programmer can then feed data to this pipeline through the first process' input channel and fetch the results through the last process' output channel.
The library provides the necessary functionality to model pipelines and handle them.
Boost.Process is constructed with portability in mind. Both the POSIX process management model and the Windows one are taken into account in the library and are supported by its API. More details are available in the Platforms and compilers chapter.
To achieve this goal, the library provides a common and system-agnostic API that lets the developer manage processes without ever knowing the operating system the code is running on. However, it is a fact that each operating system provides specific and useful features that are not portable to others; these must not be banned to developers if they need them. Therefore, the library provides a way to access these features that is clearly separated from the cross-platform API to avoid introducing portability bugs by mistake.
Boost.Process is modelled around a set of abstract concepts that are implemented in the form of C++ templates and classes. This allows the developer to replace any part of the library with custom implementations as long as they match the requirements of each concept, useful when he may need extreme performance or highly OS-specific functionality not provided by the standard classes.
The library comes with a very complete set of regression tests to ensure that it behaves according to its specifications. These tests try to be as complete as possible and are an excellent tool to verify that the library works correctly on a platform where it has not been tested before.
Although the library was not developed following the Test Driven Development (TDD) methodology, it is still interesting to have as much automated tests as possible. Whenever a bug is found or a new functionality is added, a new test must be introduced to ensure that no regressions appear and that the fixed/new code works as expected.
The library is implemented with efficiency in mind although this is not a primary goal of its development. Improvements to efficiency are of course welcome but are a second class item in front of the other goals. However, it is understandable that efficiency can be a very important feature for some developers. Therefore the programmer is allowed to replace parts of the framework with custom implementations to improve the areas that may not be efficient enough.