An HPX component is a kind of remote object. Unlike the simple HPX
Action of the previous lesson, a component can have state. Because
the component is a more complex entity, a lot more boiler plate code
is required. To assist in creation of the boiler plate, you can use
the pxi preprocessor.
The PXI preprocessor can be found in the Parallex svn tree as a
sibling to HPX (pxi_preprocessor). Building is performed with cmake, and it requires
at least Boost 1.43.
Underneath the pxi_preprocessor directory is another called "examples".
In here you will find a sort of "hello world" for components. Follow these
steps to build your own component:
// Comments are like this component A { // Fields have types and, optionally, initial values. int a = 3; int b = 9; int *n; // Methods can only be prototypes. No actual code can go here. int bar(); void print(std::string); void setb(int); int getb(); }Running pxipp on this file produces A.cpp and A.hpp. These files contain all the boiler plate code for the component.
int A::server::bar() { return 666; } void A::server::print(std::string s) { std::cout << s << std::endl; } void A::server::setb(int nb) { b = nb; } int A::server::getb() { return b; }This code looks very similar to what you would write for the implementation of a C++ class, except the name is a little different. Instead of "int A::bar() { ... }" we have to write "int A::server::bar() { ... }"
#include "A.hpp" #include <hpx/hpx_init.hpp> #include <hpx/runtime/components/component_type.hpp> int hpx_main(po::variables_map& vm) { // get a prefix hpx::naming::gid_type prefix( hpx::applier::get_applier().get_runtime_support_raw_gid()); // create a gid hpx::naming::id_type agid( prefix, hpx::naming::id_type::unmanaged); // instantiate a client A::client cli; // connect the client to a gid cli.create(agid); // start using the client cli.print("hello, world"); std::cout << cli.bar() << std::endl; std::string s("hello, world"); cli.setb(12); std::cout << "cli=" << (int)cli.getb() << std::endl; cli.print(s); A::client cli2(cli.get_gid()); std::cout << "cli2=" << (int)cli2.getb() << std::endl; hpx::components::stubs::runtime_support::shutdown_all(); return hpx::threads::terminated; } int main(int argc, char* argv[]) { // Configure application-specific options po::options_description desc_commandline("Usage: A_exe [hpx_options]"); // Initialize and run HPX int retcode = hpx_init(desc_commandline, argc, argv); return retcode; }Note that I use the hpx_init() package to startup hpx and process the arguments. This isn't strictly necessary, but is a good idea.
project(preprocessor_example) cmake_minimum_required(VERSION 2.6) set(HPX_MAJOR_VERSION 0) set(HPX_MINOR_VERSION 2) set(HPX_PATCH_LEVEL 0) set(HPX_VERSION "${HPX_MAJOR_VERSION}.${HPX_MINOR_VERSION}.${HPX_PATCH_LEVEL}") set(HPX_SOVERSION ${HPX_MAJOR_VERSION}) include($ENV{HPX_ROOT}/share/cmake/Hpx.cmake) find_program(pxipp_exe NAMES pxipp PATHS $ENV{HOME}/bin ${CMAKE_SOURCE_DIR} ${CMAKE_SOURCE_DIR}/.. .. DOC "PXI Preprocessor") message("PXI Preprocessor: ${pxipp_exe}") add_custom_command( OUTPUT A.cpp A.hpp DEPENDS A.pxi COMMAND ${pxipp_exe} A.pxi) add_hpx_component(A SOURCES A.cpp HEADERS A.hpp A_impl.hpp) add_hpx_executable(A SOURCES A_main.cpp DEPENDENCIES A_component)Notice that that you don't need to tell the system how to find Boost, or figure out the steps for linking either the shared library, or your executable. All you have to do is set the HPX_ROOT variable to point to your HPX installation.
[hpx] ini_path = ${ini_path}:.The second is named for the component itself, A.ini
[hpx.components.A] name = A path = .