C++ API
Flock provides a modern C++ API. It offers a more intuitive interface using C++ features like RAII, exceptions, and STL containers.
Important
To use the C++ API when using cmake, link again the flock::cxx-headers target
in addition to the appropriate flock::client or flock::server targets.
Prerequisites
The C++ API requires Thallium and a C++17 compatible compiler:
spack install mochi-flock +bedrock
spack install mochi-thallium
Include headers
#include <flock/cxx/server.hpp> // if server API is required
#include <flock/cxx/client.hpp> // if client API is required
#include <flock/cxx/group.hpp>
#include <flock/cxx/group-view.hpp>
Provider (server-side)
Here’s a complete example of creating a Flock provider:
/*
* (C) 2024 The University of Chicago
*
* See COPYRIGHT in top-level directory.
*/
#include <thallium.hpp>
#include <flock/cxx/server.hpp>
#include <iostream>
namespace tl = thallium;
int main(int argc, char** argv)
{
(void)argc;
(void)argv;
// Initialize Thallium engine
tl::engine engine("na+sm", THALLIUM_SERVER_MODE);
std::cout << "Server running at address: " << engine.self() << std::endl;
// Initialize group view with self as the only member
flock::GroupView initial_view;
uint16_t provider_id = 42;
// Add self to the group view
std::string my_address = static_cast<std::string>(engine.self());
initial_view.members().add(my_address.c_str(), provider_id);
// Provider configuration (static backend)
std::string config = R"(
{
"group": {
"type": "static",
"config": {}
}
}
)";
// Create Flock provider
flock::Provider provider(engine, provider_id, config.c_str(), initial_view);
std::cout << "Flock provider registered with provider_id="
<< provider_id << std::endl;
// Wait for finalize
engine.wait_for_finalize();
return 0;
}
The Provider class uses RAII - it registers on construction and
deregisters on destruction.
Client
Here’s a complete example of using the Flock client:
/*
* (C) 2024 The University of Chicago
*
* See COPYRIGHT in top-level directory.
*/
#include <thallium.hpp>
#include <flock/cxx/client.hpp>
#include <flock/cxx/group.hpp>
#include <iostream>
#include <cstdlib>
namespace tl = thallium;
int main(int argc, char** argv)
{
if(argc != 3) {
std::cerr << "Usage: " << argv[0]
<< " <server_address> <provider_id>" << std::endl;
return -1;
}
std::string server_addr_str = argv[1];
uint16_t provider_id = std::atoi(argv[2]);
// Initialize Thallium engine
tl::engine engine("na+sm", THALLIUM_CLIENT_MODE);
// Initialize Flock client
flock::Client client(engine);
// Lookup server address
tl::endpoint server_endpoint = engine.lookup(server_addr_str);
// Create group handle
flock::GroupHandle group = client.makeGroupHandle(
server_endpoint.get_addr(), provider_id, 0);
std::cout << "Connected to Flock group" << std::endl;
// Get group view
flock::GroupView view = group.view();
std::cout << "\n=== Group Information ===" << std::endl;
std::cout << "Group size: " << view.members().count() << " members" << std::endl;
std::cout << "View digest: " << view.digest() << std::endl;
// Print all members
std::cout << "\nGroup members:" << std::endl;
auto members = view.members();
for(size_t i = 0; i < members.count(); i++) {
auto member = members[i];
std::cout << " [" << i << "] Address: " << member.address << std::endl;
std::cout << " Provider ID: " << member.provider_id << std::endl;
}
// Print metadata if any
auto metadata = view.metadata();
if(metadata.count() > 0) {
std::cout << "\nMetadata:" << std::endl;
for(size_t i = 0; i < metadata.count(); i++) {
auto md = metadata[i];
std::cout << " " << md.key << " = " << md.value << std::endl;
}
}
std::cout << "\nFlock C++ client operations completed successfully" << std::endl;
return 0;
}
The client is automatically finalized when the Client object is destroyed.
Group view operations
The C++ API provides a GroupView class:
Adding members:
flock::GroupView view;
view.members().add("na+sm://12345-0", 42);
view.members().add("na+sm://12345-1", 42);
Adding metadata:
view.metadata().add("service", "my_service");
view.metadata().add("version", "1.0.0");
Accessing members:
auto members = view.members();
size_t count = members.count();
for(size_t i = 0; i < count; i++) {
auto member = members[i];
std::cout << "Member " << i << ": "
<< member.address << " (id=" << member.provider_id << ")\n";
}
Accessing metadata:
auto metadata = view.metadata();
for(size_t i = 0; i < metadata.count(); i++) {
auto md = metadata[i];
std::cout << md.key << " = " << md.value << "\n";
}