Finalization callbacks
In the previous tutorial, we have seen how to implement a provider class using Thallium. It may be convenient for a provider to know when the engine is being finalized, so as to carry out any necessary cleanup.
The following code sample illustrates another version of our custom
provider class, my_sum_provider, which pushes a finalization callback
that will be executed when the engine is finalized.
#include <iostream>
#include <thallium.hpp>
#include <thallium/serialization/stl/string.hpp>
namespace tl = thallium;
class my_sum_provider : public tl::provider<my_sum_provider> {
private:
tl::remote_procedure m_prod;
tl::remote_procedure m_sum;
tl::remote_procedure m_hello;
tl::remote_procedure m_print;
void prod(const tl::request& req, int x, int y) {
std::cout << "Computing " << x << "*" << y << std::endl;
req.respond(x+y);
}
int sum(int x, int y) {
std::cout << "Computing " << x << "+" << y << std::endl;
return x+y;
}
void hello(const std::string& name) {
std::cout << "Hello, " << name << std::endl;
}
int print(const std::string& word) {
std::cout << "Printing " << word << std::endl;
return word.size();
}
void cleanup() {
std::cout << "Provider with ID " << get_provider_id() << " is being cleaned up" << std::endl;
}
public:
my_sum_provider(tl::engine& e, uint16_t provider_id=1)
: tl::provider<my_sum_provider>(e, provider_id)
// keep the RPCs in remote_procedure objects so we can deregister them.
, m_prod(define("prod", &my_sum_provider::prod))
, m_sum(define("sum", &my_sum_provider::sum))
, m_hello(define("hello", &my_sum_provider::hello))
, m_print(define("print", &my_sum_provider::print, tl::ignore_return_value()))
{
// setup a finalization callback for this provider, in case it is
// still alive when the engine is finalized.
get_engine().push_finalize_callback(this, [this]() { cleanup(); });
}
~my_sum_provider() {
m_prod.deregister();
m_sum.deregister();
m_hello.deregister();
m_print.deregister();
// pop the finalize callback. If this destructor was called
// from the finalization callback, there is nothing to pop
get_engine().pop_finalize_callback(this);
}
};
int main(int argc, char** argv) {
tl::engine myEngine("tcp", THALLIUM_SERVER_MODE);
myEngine.enable_remote_shutdown();
std::cout << "Server running at address " << myEngine.self()
<< " with provider ids 22 and 23 " << std::endl;
// create the provider instances
my_sum_provider myProvider22(myEngine, 22);
my_sum_provider myProvider23(myEngine, 23);
myEngine.wait_for_finalize();
// the finalization callbacks will ensure that providers are freed.
return 0;
}
push_finalize_callback installs a callback that will be called
when the engine is finalized, after Mercury resources have been destroyed.
Hence, such a callback cannot make RPC calls.
Another method, push_prefinalize_callback, can be used to install
a callback to invoke when the engine is being finalized but before any
cleanup of the Mercury resources.