Commit 10a49baa authored by Dominik Charousset's avatar Dominik Charousset

Implement DCLP for singletons

The new singleton instantiation pattern fixes #152 and closes #153.
parent 14ab6004
......@@ -17,9 +17,10 @@
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#ifndef CAF_SINGLETON_MANAGER_HPP
#define CAF_SINGLETON_MANAGER_HPP
#ifndef CAF_DETAIL_SINGLETONS_HPP
#define CAF_DETAIL_SINGLETONS_HPP
#include <mutex>
#include <atomic>
#include <cstddef> // size_t
......@@ -43,12 +44,10 @@ class abstract_singleton {
};
class singletons {
singletons() = delete;
public:
singletons() = delete;
static constexpr size_t max_plugin_singletons = 3;
static constexpr size_t max_plugins = 3;
static constexpr size_t middleman_plugin_id = 0; // io lib
......@@ -82,29 +81,21 @@ class singletons {
static void stop_singletons();
private:
static std::mutex& get_mutex();
static std::atomic<abstract_singleton*>& get_plugin_singleton(size_t id);
/*
* Type `T` has to provide: `static T* create_singleton()`,
* `void initialize()`, `void stop()`, and `dispose()`.
*/
template <class T, typename Factory>
// Get instance from @p ptr or crate it on-the-fly using DCLP
template <class T, class Factory>
static T* lazy_get(std::atomic<T*>& ptr, Factory f) {
T* result = ptr.load();
while (result == nullptr) {
auto tmp = f();
// double check if singleton is still undefined
if (ptr.load() == nullptr) {
tmp->initialize();
if (ptr.compare_exchange_weak(result, tmp)) {
result = tmp;
} else {
tmp->stop();
tmp->dispose();
}
} else {
tmp->dispose();
auto result = ptr.load(std::memory_order_acquire);
if (result == nullptr) {
std::lock_guard<std::mutex> guard(get_mutex());
result = ptr.load(std::memory_order_relaxed);
if (result == nullptr) {
result = f();
result->initialize();
ptr.store(result, std::memory_order_release);
}
}
return result;
......@@ -123,21 +114,20 @@ class singletons {
template <class T>
static void dispose(std::atomic<T*>& ptr) {
for (;;) {
auto p = ptr.load();
for (;;) {
if (p == nullptr) {
return;
} else if (ptr.compare_exchange_weak(p, nullptr)) {
}
if (ptr.compare_exchange_weak(p, nullptr)) {
p->dispose();
ptr = nullptr;
return;
}
}
}
};
} // namespace detail
} // namespace caf
#endif // CAF_SINGLETON_MANAGER_HPP
#endif // CAF_DETAIL_SINGLETONS_HPP
......@@ -35,7 +35,9 @@ namespace detail {
namespace {
std::atomic<abstract_singleton*> s_plugins[singletons::max_plugin_singletons];
std::mutex s_singletons_mtx;
std::atomic<abstract_singleton*> s_plugins[singletons::max_plugins];
std::atomic<scheduler::abstract_coordinator*> s_scheduling_coordinator;
std::atomic<uniform_type_info_map*> s_uniform_type_info_map;
std::atomic<actor_registry*> s_actor_registry;
......@@ -49,7 +51,12 @@ abstract_singleton::~abstract_singleton() {
// nop
}
std::mutex& singletons::get_mutex() {
return s_singletons_mtx;
}
void singletons::stop_singletons() {
// stop singletons, i.e., make sure no background threads/actors are running
CAF_LOGF_DEBUG("stop scheduler");
stop(s_scheduling_coordinator);
CAF_LOGF_DEBUG("stop plugins");
......@@ -64,7 +71,7 @@ void singletons::stop_singletons() {
stop(s_uniform_type_info_map);
stop(s_logger);
stop(s_node_id);
// dispose singletons
// dispose singletons, i.e., release memory
dispose(s_scheduling_coordinator);
for (auto& plugin : s_plugins) {
dispose(plugin);
......@@ -92,9 +99,8 @@ scheduler::abstract_coordinator* singletons::get_scheduling_coordinator() {
return lazy_get(s_scheduling_coordinator);
}
bool singletons::set_scheduling_coordinator(scheduler::abstract_coordinator* p) {
scheduler::abstract_coordinator* expected = nullptr;
return s_scheduling_coordinator.compare_exchange_weak(expected, p);
bool singletons::set_scheduling_coordinator(scheduler::abstract_coordinator*p) {
return lazy_get(s_scheduling_coordinator, [p] { return p; }) == p;
}
node_id singletons::get_node_id() {
......@@ -106,7 +112,7 @@ logging* singletons::get_logger() {
}
std::atomic<abstract_singleton*>& singletons::get_plugin_singleton(size_t id) {
CAF_REQUIRE(id < max_plugin_singletons);
CAF_REQUIRE(id < max_plugins);
return s_plugins[id];
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment