Boost C++ Libraries Home Libraries People FAQ More

PrevUpHomeNext

Tutorials

Child.1 - Starting a child
Child.2 - Waiting for a child to terminate
Child.3 - Reading from a child with a standard C++ stream
Child.4 - Reading from a child using asynchronous I/O
Environment.1 - Starting a child with an empty environment
Environment.2 - Starting a child with the current environment
Environment.3 - Starting a child with a modified environment
POSIX child.1 - Accessing status codes of a terminated child
POSIX child.2 - Using more than three communication streams
Windows child.1 - Setting up a context with startup information
Windows child.2 - Accessing process and thread identifiers and handles
Pipeline.1 - Creating children and connecting their streams

Child.1 - Starting a child

The smallest program to start a child consists of specifying the executable name and the arguments, setting up the context and calling a free-standing function to launch the process.

// 
// Boost.Process 
// ~~~~~~~~~~~~~ 
// 
// Copyright (c) 2006, 2007 Julio M. Merino Vidal 
// Copyright (c) 2008 Boris Schaeling 
// 
// Distributed under the Boost Software License, Version 1.0. (See accompanying 
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 
// 

#include <boost/process.hpp> 
#include <string> 
#include <vector> 

namespace bp = ::boost::process; 

int main() 
{ 
    std::string exec = "bjam"; 

    std::vector<std::string> args; 
    args.push_back("--version"); 

    bp::context ctx; 
    ctx.stdout_behavior = bp::silence_stream(); 

    bp::child c = bp::launch(exec, args, ctx); 
} 

The header file boost/process.hpp can be used to declare easily all classes and functions which are defined by Boost.Process. It simply includes all header files. Instead of including boost/process.hpp the program would also compile if the header files boost/process/context.hpp, boost/process/stream_behavior.hpp, boost/process/operations.hpp and boost/process/child.hpp would have been included.

In order to start a process the executable name and the arguments must be specified and a context must be setup. While the executable name is simply a std::string and arguments are stored in a std::vector<std::string> the context is a class from Boost.Process. It provides three properties stdin_behavior, stdout_behavior and stderr_behavior to specify the behavior of the stdin, stdout and stderr streams. By default all streams are closed. If a child should be able to read from or write to some of these streams they need to be configured. Boost.Process provides a few helper functions - among others silence_stream. With silence_stream a stream is not closed but all data written to it is discarded. For the program above it means that bjam can print the version number as the stdout stream is available. However the version number is written to a null device.

The free-standing function launch returns a child object. If a parent does not want to communicate with a child nor wait for its termination it can simply forget about it. When the child object goes out of scope and is destroyed the parent can not reach the child anymore. However the child may still be running and even might outlive the parent.

Child.2 - Waiting for a child to terminate

When a child has been started wait can be called to wait for the child to terminate.

// 
// Boost.Process 
// ~~~~~~~~~~~~~ 
// 
// Copyright (c) 2006, 2007 Julio M. Merino Vidal 
// Copyright (c) 2008 Boris Schaeling 
// 
// Distributed under the Boost Software License, Version 1.0. (See accompanying 
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 
// 

#include <boost/process.hpp> 
#include <string> 
#include <vector> 

namespace bp = ::boost::process; 

bp::child start_child() 
{ 
    std::string exec = "bjam"; 

    std::vector<std::string> args; 
    args.push_back("--version"); 

    bp::context ctx; 
    ctx.stdout_behavior = bp::silence_stream(); 

    return bp::launch(exec, args, ctx); 
} 

int main() 
{ 
    bp::child c = start_child(); 

    bp::status s = c.wait(); 

    return s.exited() ? s.exit_status() : EXIT_FAILURE; 
} 

wait returns a status object when the child has terminated. As long as the child is running wait does not return but blocks.

The returned status object can be used to check the exit code of the child via exit_status. Before exit_status is called though the return value of exited should be checked to make sure the child exited gracefully. Only if exited returns true exit_status may be called.

Child.3 - Reading from a child with a standard C++ stream

Boost.Process can not only be used to start a child and wait for its termination. It also enables a parent to communicate with a child via standard C++ streams.

// 
// Boost.Process 
// ~~~~~~~~~~~~~ 
// 
// Copyright (c) 2006, 2007 Julio M. Merino Vidal 
// Copyright (c) 2008 Boris Schaeling 
// 
// Distributed under the Boost Software License, Version 1.0. (See accompanying 
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 
// 

#include <boost/process.hpp> 
#include <string> 
#include <vector> 
#include <iostream> 

namespace bp = ::boost::process; 

bp::child start_child() 
{ 
    std::string exec = "bjam"; 

    std::vector<std::string> args; 
    args.push_back("--version"); 

    bp::context ctx; 
    ctx.stdout_behavior = bp::capture_stream(); 

    return bp::launch(exec, args, ctx); 
} 

int main() 
{ 
    bp::child c = start_child(); 

    bp::pistream &is = c.get_stdout(); 
    std::string line; 
    while (std::getline(is, line)) 
        std::cout << line << std::endl; 
} 

When a child has been started the stdin, stdout and stderr streams can be fetched by calling get_stdin, get_stdout and get_stderr. As all streams are closed by default it's required to change the behavior of a stream prior to starting a child! If for example the parent wants to read what the child writes to stdout the behavior of the stdout stream must be changed to capture_stream. Only then the parent can access the stdout stream of the child.

While stdout is a stream the child writes data to from the parent's point of view it's an input stream. That's why get_stdout returns a pistream object. As pistream is derived from std::istream it behaves like any other standard C++ stream. The only additional method available in pistream is close which can be called to close a stream and notify the child that the parent does not want to read any more data.

As pistream behaves like a standard C++ stream all method calls can block. If the stream buffer is empty and the child doesn't write any data to the stream currently the parent will wait until there is new data written to the stream buffer. If it's not acceptable to block asynchronous I/O should be used.

Child.4 - Reading from a child using asynchronous I/O

While Boost.Process does not support aysynchronous I/O out of the box it provides methods to access the underlying handles of a stream which can be assigned to Asio objects.

// 
// Boost.Process 
// ~~~~~~~~~~~~~ 
// 
// Copyright (c) 2006, 2007 Julio M. Merino Vidal 
// Copyright (c) 2008 Boris Schaeling 
// 
// Distributed under the Boost Software License, Version 1.0. (See accompanying 
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 
// 

#if defined(__CYGWIN__) 
#  define _WIN32_WINNT 0x0501 
#  define __USE_W32_SOCKETS 
#  undef BOOST_POSIX_API 
#  define BOOST_WINDOWS_API 
#endif 
#include <boost/asio.hpp> 
#define BOOST_PROCESS_WINDOWS_USE_NAMED_PIPE 
#include <boost/process.hpp> 
#include <boost/array.hpp> 
#include <boost/bind.hpp> 
#include <string> 
#include <vector> 
#include <iostream> 

namespace bp = ::boost::process; 
namespace ba = ::boost::asio; 

ba::io_service io_service; 
boost::array<char, 4096> buffer; 

#if defined(BOOST_POSIX_API) 
ba::posix::stream_descriptor in(io_service); 
#elif defined(BOOST_WINDOWS_API) 
ba::windows::stream_handle in(io_service); 
#else 
#  error "Unsupported platform." 
#endif 

bp::child start_child() 
{ 
    std::string exec = "bjam"; 

    std::vector<std::string> args; 
    args.push_back("--version"); 

    bp::context ctx; 
    ctx.stdout_behavior = bp::capture_stream(); 

    return bp::launch(exec, args, ctx); 
} 

void end_read(const boost::system::error_code &ec, std::size_t bytes_transferred); 

void begin_read() 
{ 
    in.async_read_some(boost::asio::buffer(buffer), 
        boost::bind(&end_read, ba::placeholders::error, ba::placeholders::bytes_transferred)); 
} 

void end_read(const boost::system::error_code &ec, std::size_t bytes_transferred) 
{ 
    if (!ec) 
    { 
        std::cout << std::string(buffer.data(), bytes_transferred) << std::flush; 
        begin_read(); 
    } 
} 

int main() 
{ 
    bp::child c = start_child(); 

    bp::pistream &is = c.get_stdout(); 
    in.assign(is.handle().release()); 

    begin_read(); 

    c.wait(); 
} 

Asio provides the classes stream_descriptor and stream_handle to use file descriptors on POSIX platforms and HANDLEs on Windows for asynchronous I/O. By calling handle an object is returned with owns the underlying handle. In order to access the underlying handle and assign it to a Asio object release must be called. Ownership of the underlying handle will be transferred to the caller which means the streams won't be closed when the child object goes out of scope.

Please note that the macro BOOST_PROCESS_WINDOWS_USE_NAMED_PIPE must be defined for asynchronous I/O to work on Windows platforms. By default streams use anonymous pipes which don't support asynchronous I/O on Windows though. By defining BOOST_PROCESS_WINDOWS_USE_NAMED_PIPE named pipes are used on Windows which support asynchronous I/O.

Once the underlying handles have been assigned to Asio objects asynchronous I/O works like usual. To make sure that the parent waits for the child to write data and does not terminate wait is called.

Environment.1 - Starting a child with an empty environment

When a context is setup the environment table which contains environment variables for the new process can be configured. By default the environment table is empty.

// 
// Boost.Process 
// ~~~~~~~~~~~~~ 
// 
// Copyright (c) 2006, 2007 Julio M. Merino Vidal 
// Copyright (c) 2008 Boris Schaeling 
// 
// Distributed under the Boost Software License, Version 1.0. (See accompanying 
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 
// 

#include <boost/process.hpp> 
#include <string> 
#include <vector> 
#include <iostream> 

namespace bp = ::boost::process; 

bp::child start_child(bp::context ctx) 
{ 
#if defined(BOOST_POSIX_API) 
    return bp::launch(std::string("env"), std::vector<std::string>(), ctx); 
#elif defined(BOOST_WINDOWS_API) 
    return bp::launch_shell("set", ctx); 
#else 
#  error "Unsupported platform." 
#endif 
} 

int main() 
{ 
    bp::context ctx; 
    ctx.stdout_behavior = bp::capture_stream(); 

    bp::child c = start_child(ctx); 

    bp::pistream &is = c.get_stdout(); 
    std::string line; 
    while (std::getline(is, line)) 
        std::cout << line << std::endl; 
} 

The child started simply writes the environment variables to the stdout stream. As different commands have to be used on POSIX and Windows platforms the macros BOOST_POSIX_API and BOOST_WINDOWS_API are used. They are automatically available when boost/process.hpp is included.

On POSIX platforms the program env is used to print environment variables. On Windows a built-in shell command has to be used. As the built-in shell command is not a stand-alone executable the free-standing function launch_shell must be called. This function starts the shell (cmd.exe on Windows) and passes the command as an argument to the shell.

When the program is run which reads the data written to stdout by the child no data is received: By default the environment table is empty.

Environment.2 - Starting a child with the current environment

If a child should see the same environment variables as the parent process the context has to be setup accordingly.

// 
// Boost.Process 
// ~~~~~~~~~~~~~ 
// 
// Copyright (c) 2006, 2007 Julio M. Merino Vidal 
// Copyright (c) 2008 Boris Schaeling 
// 
// Distributed under the Boost Software License, Version 1.0. (See accompanying 
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 
// 

#include <boost/process.hpp> 
#include <string> 
#include <vector> 
#include <iostream> 

namespace bp = ::boost::process; 

bp::child start_child(bp::context ctx) 
{ 
#if defined(BOOST_POSIX_API) 
    return bp::launch(std::string("env"), std::vector<std::string>(), ctx); 
#elif defined(BOOST_WINDOWS_API) 
    return bp::launch_shell("set", ctx); 
#else 
#  error "Unsupported platform." 
#endif 
} 

int main() 
{ 
    bp::context ctx; 
    ctx.stdout_behavior = bp::capture_stream(); 
    ctx.environment = bp::self::get_environment(); 

    bp::child c = start_child(ctx); 

    bp::pistream &is = c.get_stdout(); 
    std::string line; 
    while (std::getline(is, line)) 
        std::cout << line << std::endl; 
} 

By calling current_environment the current environment can be copied to the property environment of a context. When the program is run the very same environment variables as seen by the parent are printed.

Environment.3 - Starting a child with a modified environment

If a child should not see some environment variables or needs other environment variables to be defined the environment table can be modified.

// 
// Boost.Process 
// ~~~~~~~~~~~~~ 
// 
// Copyright (c) 2006, 2007 Julio M. Merino Vidal 
// Copyright (c) 2008 Boris Schaeling 
// 
// Distributed under the Boost Software License, Version 1.0. (See accompanying 
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 
// 

#include <boost/process.hpp> 
#include <string> 
#include <vector> 
#include <iostream> 

namespace bp = ::boost::process; 

bp::child start_child(bp::context ctx) 
{ 
#if defined(BOOST_POSIX_API) 
    return bp::launch(std::string("env"), std::vector<std::string>(), ctx); 
#elif defined(BOOST_WINDOWS_API) 
    return bp::launch_shell("set", ctx); 
#else 
#  error "Unsupported platform." 
#endif 
} 

int main() 
{ 
    bp::context ctx; 
    ctx.stdout_behavior = bp::capture_stream(); 
    ctx.environment = bp::self::get_environment(); 
    ctx.environment.erase("TMP"); 
    ctx.environment.insert(bp::environment::value_type("MYNEWVAR", "VALUE")); 

    bp::child c = start_child(ctx); 

    bp::pistream &is = c.get_stdout(); 
    std::string line; 
    while (std::getline(is, line)) 
        std::cout << line << std::endl; 
} 

The property environment of the context is a typedef for std::map<std::string, std::string>. Thus it's easy to modify the environment table and remove or insert environment variables.

POSIX child.1 - Accessing status codes of a terminated child

While status is typically used to check the exit status of a terminated child on POSIX platforms the class posix_status provides more methods to find out why and how a child terminated.

// 
// Boost.Process 
// ~~~~~~~~~~~~~ 
// 
// Copyright (c) 2006, 2007 Julio M. Merino Vidal 
// Copyright (c) 2008 Boris Schaeling 
// 
// Distributed under the Boost Software License, Version 1.0. (See accompanying 
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 
// 

#include <boost/process.hpp> 
#if defined(BOOST_POSIX_API) 
#include <string> 
#include <vector> 
#include <iostream> 
#include <cstdlib> 

namespace bp = ::boost::process; 

bp::child start_child(std::string exec) 
{ 
    std::vector<std::string> args; 

    bp::context ctx; 
    ctx.stdin_behavior = bp::inherit_stream(); 
    ctx.stdout_behavior = bp::inherit_stream(); 
    ctx.stderr_behavior = bp::inherit_stream(); 

    return bp::launch(exec, args, ctx); 
} 

int main(int argc, char *argv[]) 
{ 
    if (argc < 2) 
    { 
        std::cerr << "Please provide a program name" << std::endl; 
        return EXIT_FAILURE; 
    } 

    bp::child c = start_child(argv[1]); 

    bp::posix_status s = c.wait(); 
    if (s.exited()) 
        std::cout << "Program returned exit code " << s.exit_status() << std::endl; 
    else if (s.signaled()) 
    { 
        std::cout << "Program received signal " << s.term_signal() << std::endl; 
        if (s.dumped_core()) 
            std::cout << "Program also dumped core" << std::endl; 
    } 
    else if (s.stopped()) 
        std::cout << "Program stopped by signal " << s.stop_signal() << std::endl; 
    else 
        std::cout << "Unknown termination reason" << std::endl; 

    return s.exited() ? s.exit_status() : EXIT_FAILURE; 
} 
#endif 

The methods signaled and stopped can be called to check if the process exited due to an external signal or was stopped by an external signal. If they return true additional methods can be called to get the signal code.

POSIX child.2 - Using more than three communication streams

On POSIX platforms it's possible to setup more communication streams than stdin, stdout and stderr.

// 
// Boost.Process 
// ~~~~~~~~~~~~~ 
// 
// Copyright (c) 2006, 2007 Julio M. Merino Vidal 
// Copyright (c) 2008 Boris Schaeling 
// 
// Distributed under the Boost Software License, Version 1.0. (See accompanying 
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 
// 

#include <boost/process.hpp> 
#if defined(BOOST_POSIX_API) 
#include <string> 
#include <vector> 
#include <iostream> 
#include <cstdlib> 
#include <unistd.h> 

namespace bp = ::boost::process; 

bp::posix_child start_child() 
{ 
    std::string exec = bp::find_executable_in_path("dbus-daemon"); 

    std::vector<std::string> args; 
    args.push_back("--fork"); 
    args.push_back("--session"); 
    args.push_back("--print-address=3"); 
    args.push_back("--print-pid=4"); 

    bp::posix_context ctx; 
    ctx.output_behavior.insert(bp::behavior_map::value_type(STDOUT_FILENO, bp::inherit_stream())); 
    ctx.output_behavior.insert(bp::behavior_map::value_type(STDERR_FILENO, bp::inherit_stream())); 
    ctx.output_behavior.insert(bp::behavior_map::value_type(3, bp::capture_stream())); 
    ctx.output_behavior.insert(bp::behavior_map::value_type(4, bp::capture_stream())); 

    return bp::posix_launch(exec, args, ctx); 
} 

int main() 
{ 
    try 
    { 
        bp::posix_child c = start_child(); 

        std::string address; 
        pid_t pid; 
        c.get_output(3) >> address; 
        c.get_output(4) >> pid; 

        bp::status s = c.wait(); 
        if (s.exited()) 
        { 
            if (s.exit_status() == EXIT_SUCCESS) 
            { 
                std::cout << "D-BUS daemon's address is: " << address << std::endl; 
                std::cout << "D-BUS daemon's PID is: " << pid << std::endl; 
            } 
            else 
                std::cout << "D-BUS daemon returned error condition: " << s.exit_status() << std::endl; 
        } 
        else 
            std::cout << "D-BUS daemon terminated abnormally" << std::endl; 

        return s.exited() ? s.exit_status() : EXIT_FAILURE; 
    } 
    catch (boost::filesystem::filesystem_error &ex) 
    { 
        std::cout << ex.what() << std::endl; 
        return EXIT_FAILURE; 
    } 
} 
#endif 

The class posix_context provides the properties input_behavior and output_behavior to add and configure more streams than stdin, stdout and stderr. When started those streams can be accessed by calling get_intput and get_output on posix_child.

Windows child.1 - Setting up a context with startup information

With win32_context it's possible to add a STARTUPINFO structure which will be used by win32_launch to start a Windows process.

// 
// Boost.Process 
// ~~~~~~~~~~~~~ 
// 
// Copyright (c) 2006, 2007 Julio M. Merino Vidal 
// Copyright (c) 2008 Boris Schaeling 
// 
// Distributed under the Boost Software License, Version 1.0. (See accompanying 
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 
// 

#include <boost/process.hpp> 
#if defined(BOOST_WINDOWS_API) 
#include <string> 
#include <vector> 
#include <iostream> 
#include <windows.h> 

namespace bp = ::boost::process; 

bp::win32_child start_child() 
{ 
    std::string exec = bp::find_executable_in_path("notepad"); 

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

    STARTUPINFO si; 
    ::ZeroMemory(&si, sizeof(si)); 
    si.cb = sizeof(si); 
    si.dwFlags |= STARTF_USEPOSITION | STARTF_USESIZE; 
    si.dwX = 0; 
    si.dwY = 0; 
    si.dwXSize = 640; 
    si.dwYSize = 480; 

    bp::win32_context ctx; 
    ctx.startupinfo = &si; 

    return bp::win32_launch(exec, args, ctx); 
} 

int main() 
{ 
    try 
    { 
        bp::win32_child c = start_child(); 
    } 
    catch (boost::filesystem::filesystem_error &ex) 
    { 
        std::cout << ex.what() << std::endl; 
    } 
} 
#endif 

The STARTUPINFO structure enables developers to specify for example location and size of the main window of the new process.

Windows child.2 - Accessing process and thread identifiers and handles

If it's required to access process and thread identifiers and handles on Windows platforms a child should be started with win32_launch.

// 
// Boost.Process 
// ~~~~~~~~~~~~~ 
// 
// Copyright (c) 2006, 2007 Julio M. Merino Vidal 
// Copyright (c) 2008 Boris Schaeling 
// 
// Distributed under the Boost Software License, Version 1.0. (See accompanying 
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 
// 

#include <boost/process.hpp> 
#if defined(BOOST_WINDOWS_API) 
#include <string> 
#include <vector> 
#include <iostream> 
#include <windows.h> 

namespace bp = ::boost::process; 

bp::win32_child start_child() 
{ 
    std::string exec = bp::find_executable_in_path("notepad"); 

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

    bp::win32_context ctx; 

    return bp::win32_launch(exec, args, ctx); 
} 

int main() 
{ 
    try 
    { 
        bp::win32_child c = start_child(); 

        std::cout << "Process handle            : 0x" 
            << c.get_handle() << std::endl; 
        std::cout << "Process identifier        : " 
            << c.get_id() << std::endl; 
        std::cout << "Primary thread handle     : 0x" 
            << c.get_primary_thread_handle() << std::endl; 
        std::cout << "Primary thread identifier : " 
            << c.get_primary_thread_id() << std::endl; 
    } 
    catch (boost::filesystem::filesystem_error &ex) 
    { 
        std::cout << ex.what() << std::endl; 
    } 
} 
#endif 

The function win32_launch returns a win32_child object which provides additional methods to access identifiers and handles of the child's process and primary thread.

Pipeline.1 - Creating children and connecting their streams

The library supports creating a so-called pipeline: Children are spawned in a way that an output stream is connected to the input stream of the next child.

// 
// Boost.Process 
// ~~~~~~~~~~~~~ 
// 
// Copyright (c) 2006, 2007 Julio M. Merino Vidal 
// Copyright (c) 2008 Boris Schaeling 
// 
// Distributed under the Boost Software License, Version 1.0. (See accompanying 
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 
// 

#include <boost/process.hpp> 
#include <string> 
#include <vector> 
#include <iostream> 
#include <fstream> 
#include <cstdlib> 

namespace bp = ::boost::process; 

bp::children start_children() 
{ 
    bp::context ctxin; 
    ctxin.stdin_behavior = bp::capture_stream(); 

    bp::context ctxout; 
    ctxout.stdout_behavior = bp::inherit_stream(); 
    ctxout.stderr_behavior = bp::redirect_stream_to_stdout(); 

    std::string exec1 = bp::find_executable_in_path("cut"); 
    std::vector<std::string> args1; 
    args1.push_back("-d "); 
    args1.push_back("-f2-5"); 

    std::string exec2 = bp::find_executable_in_path("sed"); 
    std::vector<std::string> args2; 
    args2.push_back("s,^,line: >>>,"); 

    std::string exec3 = bp::find_executable_in_path("sed"); 
    std::vector<std::string> args3; 
    args3.push_back("s,$,<<<,"); 

    std::vector<bp::pipeline_entry> entries; 
    entries.push_back(bp::pipeline_entry(exec1, args1, ctxin)); 
    entries.push_back(bp::pipeline_entry(exec2, args2, ctxout)); 
    entries.push_back(bp::pipeline_entry(exec3, args3, ctxout)); 

    return bp::launch_pipeline(entries); 
} 

int main(int argc, char *argv[]) 
{ 
    try 
    { 
        if (argc < 2) 
        { 
            std::cerr << "Please specify a file name" << std::endl; 
            return EXIT_FAILURE; 
        } 

        std::ifstream file(argv[1]); 
        if (!file) 
        { 
            std::cerr << "Cannot open file" << std::endl; 
            return EXIT_FAILURE; 
        } 

        bp::children cs = start_children(); 

        bp::postream &os = cs.front().get_stdin(); 
        std::string line; 
        while (std::getline(file, line)) 
            os << line << std::endl; 
        os.close(); 

        bp::status s = bp::wait_children(cs); 

        return s.exited() ? s.exit_status() : EXIT_FAILURE; 
    } 
    catch (boost::filesystem::filesystem_error &ex) 
    { 
        std::cout << ex.what() << std::endl; 
        return EXIT_FAILURE; 
    } 
} 

PrevUpHomeNext