ESPResSo
Extensible Simulation Package for Research on Soft Matter Systems
Loading...
Searching...
No Matches
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