Powerful multi-threaded coroutine dispatcher and parallel execution engine
Quantum is a full-featured and powerful C++ framework build on top of the Boost coroutine library. The framework allows users to dispatch units of work (a.k.a. tasks) as coroutines and execute them concurrently using the 'reactor' pattern.
forEach
and mapReduce
functions.Sequencer
class allowing strict FIFO ordering of tasks based on sequence ids.Quantum is very simple and easy to use:
using namespace Bloomberg::quantum;
// Define a coroutine
int getDummyValue(CoroContextPtr<int> ctx)
{
int value;
... //do some work
ctx->yield(); //be nice and let other coroutines run (optional cooperation)
... //do more work and calculate 'value'
return ctx->set(value);
}
// Create a dispatcher
Dispatcher dispatcher;
// Dispatch a work item to do some work and return a value
int result = dispatcher.post(getDummyValue)->get();
Chaining tasks can also be straightforward. In this example we produce various types in a sequence.
using namespace Bloomberg::quantum;
// Create a dispatcher
Dispatcher dispatcher;
auto ctx = dispatcher.postFirst([](CoroContextPtr<int> ctx)->int {
return ctx->set(55); //Set the 1st value
})->then([](CoroContextPtr<double> ctx)->int {
// Get the first value and add something to it
return ctx->set(ctx->getPrev<int>() + 22.33); //Set the 2nd value
})->then([](CoroContextPtr<std::string> ctx)->int {
return ctx->set("Hello world!"); //Set the 3rd value
})->finally([](CoroContextPtr<std::list<int>> ctx)->int {
return ctx->set(std::list<int>{1,2,3}); //Set 4th value
})->end();
int i = ctx->getAt<int>(0); //This will throw 'FutureAlreadyRetrievedException'
//since future was already read in the 2nd coroutine
double d = ctx->getAt<double>(1); //returns 77.33
std::string s = ctx->getAt<std::string>(2); //returns "Hello world!";
std::list<int>& listRef = ctx->getRefAt<std::list<int>>(3); //get list reference
std::list<int>& listRef2 = ctx->getRef(); //get another list reference.
//The 'At' overload is optional for last chain future
std::list<int> listValue = ctx->get(); //get list value
Chaining with the new V2 api:
using namespace Bloomberg::quantum;
// Create a dispatcher
Dispatcher dispatcher;
auto ctx = dispatcher.postFirst([](VoidContextPtr ctx)->int {
return 55; //Set the 1st value
})->then([](VoidContextPtr ctx)->double {
// Get the first value and add something to it
return ctx->getPrev<int>() + 22.33; //Set the 2nd value
})->then([](VoidContextPtr ctx)->std::string {
return "Hello world!"; //Set the 3rd value
})->finally([](VoidContextPtr ctx)->std::list<int> {
return {1,2,3}; //Set 4th value
})->end();
Quantum is a header-only library and as such no targets need to be built. To install simply run:
> cmake -Bbuild <options> .
> cd build
> make install
Various CMake options can be used to configure the output:
QUANTUM_BUILD_DOC
: Build Doxygen documentation. Default OFF
.QUANTUM_ENABLE_DOT
: Enable generation of DOT viewer files. Default OFF
.QUANTUM_VERBOSE_MAKEFILE
: Enable verbose cmake output. Default ON
.QUANTUM_ENABLE_TESTS
: Builds the tests
target. Default OFF
.QUANTUM_BOOST_STATIC_LIBS
: Link with Boost static libraries. Default ON
.QUANTUM_BOOST_USE_MULTITHREADED
: Use Boost multi-threaded libraries. Default ON
.QUANTUM_USE_DEFAULT_ALLOCATOR
: Use default system supplied allocator instead of Quantum's. Default OFF
.QUANTUM_ALLOCATE_POOL_FROM_HEAP
: Pre-allocates object pools from heap instead of the application stack. Default OFF
.QUANTUM_BOOST_USE_SEGMENTED_STACKS
: Use Boost segmented stacks for coroutines. Default OFF
.QUANTUM_BOOST_USE_PROTECTED_STACKS
: Use Boost protected stacks for coroutines (slow!). Default OFF
.QUANTUM_BOOST_USE_FIXEDSIZE_STACKS
: Use Boost fixed size stacks for coroutines. Default OFF
.QUANTUM_INSTALL_ROOT
: Specify custom install path.
Default is /usr/local/include
for Linux or c:/Program Files
for Windows.QUANTUM_PKGCONFIG_DIR
: Specify custom install path for the quantum.pc
file. Default is ${QUANTUM_INSTALL_ROOT}/share/pkgconfig
.
To specify a relative path from QUANTUM_INSTALL_ROOT
, omit leading /
.QUANTUM_EXPORT_PKGCONFIG
: Generate quantum.pc
file. Default ON
.QUANTUM_CMAKE_CONFIG_DIR
: Specify a different install directory for the project's config, target and version files. Default is ${QUANTUM_INSTALL_ROOT}/share/cmake
.QUANTUM_EXPORT_CMAKE_CONFIG
: Generate CMake config, target and version files. Default ON
.BOOST_ROOT
: Specify a different Boost install directory.GTEST_ROOT
: Specify a different GTest install directory.Note: options must be preceded with -D
when passed as arguments to CMake.
Run the following from the top directory:
> cmake -Bbuild -DQUANTUM_ENABLE_TESTS=ON <options> .
> cd build
> make quantum_test && ctest
To use the library simply include <quantum/quantum.h>
in your application. Also, the following libraries must be included in the link:
boost_context
pthread
Quantum library is fully is compatible with C++11
, C++14
and C++17
language features. See compiler options below for more details.
The following compiler options can be set when building your application:
__QUANTUM_PRINT_DEBUG
: Prints debug and error information to stdout
and stderr
respectively.__QUANTUM_USE_DEFAULT_ALLOCATOR
: Disable pool allocation for internal objects (other than coroutine stacks) and
use default system allocators instead.__QUANTUM_ALLOCATE_POOL_FROM_HEAP
: Pre-allocates object pools from heap instead of the application stack (default).
This affects internal object allocations other than coroutines. Coroutine pools are always heap-allocated due to their size.__QUANTUM_BOOST_USE_SEGMENTED_STACKS
: Uses boost segmented stack for on-demand coroutine stack growth. Note that
Boost.Context library must be built with property segmented-stacks=on
and applying BOOST_USE_UCONTEXT
and
BOOST_USE_SEGMENTED_STACKS
at b2/bjam command line.__QUANTUM_BOOST_USE_PROTECTED_STACKS
: Uses boost protected stack for runtime bound-checking. When using this option,
coroutine creation (but not runtime efficiency) becomes more expensive.__QUANTUM_BOOST_USE_FIXEDSIZE_STACKS
: Uses boost fixed size stack. This defaults to system default allocator.Various application-wide settings can be configured via ThreadTraits
, AllocatorTraits
and StackTraits
.
Please see the wiki page for a detailed overview of this library, use-case scenarios and examples.
For class description visit the API reference page.