Loading [MathJax]/extensions/TeX/AMSmath.js
ESPResSo
Extensible Simulation Package for Research on Soft Matter Systems
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages Concepts
ResourceManager.hpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2023 The ESPResSo project
3 *
4 * This file is part of ESPResSo.
5 *
6 * ESPResSo is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * ESPResSo is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#pragma once
21
22#include <list>
23#include <memory>
24#include <stack>
25#include <utility>
26
27/**
28 * @brief Manager to control the lifetime of shared resources.
29 *
30 * Resources that need to be available globally, for example
31 * via singletons, need to expire after all objects that depend
32 * on them have already expired.
33 * When static objects reside in different translation units, they
34 * can expire in any order, potentially creating race conditions
35 * if one static object relies on the other it its destructor.
36 *
37 * This class "locks" resources by storing a shared pointer to them,
38 * ensuring that the resources lifetime is extended by the lifetime
39 * of the class instance. Client code can then keep this class
40 * instance alive until the resources are no longer needed, at which
41 * point the class instance can be released. Type erasure hides
42 * implementation details of the resources being locked.
43 *
44 * Multiple resources can be locked, using a LIFO (last-in, first-out)
45 * container to ensure that resources are freed in a controlled order.
46 * This design choice avoids undefined behavior due to race conditions,
47 * which may occur if one global resource's destruction depends on the
48 * existence of another global resource. This behavior cannot be achieved
49 * with STL containers like @p std::stack or @p std::vector, since the
50 * destruction order of the stored data is under-specified.
51 */
53 class ResourceLock {
54 public:
55 virtual ~ResourceLock() = default;
56 };
57
58 template <typename T> class ResourceLockImpl : public ResourceLock {
59 std::shared_ptr<T> m_resource;
60
61 public:
62 explicit ResourceLockImpl(std::shared_ptr<T> resource)
63 : m_resource(std::move(resource)) {}
64 ~ResourceLockImpl() override { m_resource.reset(); }
65 };
66
67 template <typename T> using LifoList = std::stack<T, std::list<T>>;
68
69 LifoList<std::unique_ptr<ResourceLock>> m_resources;
70
71public:
72 ResourceManager() = default;
73
75 while (not m_resources.empty()) {
76 m_resources.pop();
77 }
78 }
79
80 template <typename T> void acquire_lock(std::shared_ptr<T> resource) {
81 m_resources.emplace(std::make_unique<ResourceLockImpl<T>>(resource));
82 }
83};
Manager to control the lifetime of shared resources.
void acquire_lock(std::shared_ptr< T > resource)
ResourceManager()=default