Mir
synchronised.h
Go to the documentation of this file.
1 /*
2  * Copyright © Canonical Ltd.
3  *
4  * This program is free software: you can redistribute it and/or modify it
5  * under the terms of the GNU Lesser General Public License version 2 or 3,
6  * as published by the Free Software Foundation.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  * GNU Lesser General Public License for more details.
12  *
13  * You should have received a copy of the GNU Lesser General Public License
14  * along with this program. If not, see <http://www.gnu.org/licenses/>.
15  */
16 
17 #ifndef MIR_SYNCHRONISED_H_
18 #define MIR_SYNCHRONISED_H_
19 
20 #include <mutex>
21 
22 namespace mir
23 {
24 
25 /**
26  * An object that enforces unique access to the data it contains
27  *
28  * This behaves like a mutex which owns the data it guards, and
29  * can give out a smart-pointer-esque handle to lock and access it.
30  *
31  * \tparam T The type of data contained
32  */
33 template<typename T>
35 {
36 public:
37  Synchronised() = default;
38  Synchronised(T&& initial_value)
39  : value{std::move(initial_value)}
40  {
41  }
42 
43  Synchronised(Synchronised const&) = delete;
44  Synchronised& operator=(Synchronised const&) = delete;
45 
46  /**
47  * Smart-pointer-esque accessor for the protected data.
48  *
49  * Ensures exclusive access to the referenced data.
50  *
51  * \note Instances of Locked must not outlive the Synchronised
52  * they are derived from.
53  */
54  template<typename U>
55  class LockedImpl
56  {
57  public:
58  LockedImpl(LockedImpl&& from) noexcept
59  : value{from.value},
60  lock{std::move(from.lock)}
61  {
62  from.value = nullptr;
63  }
64 
65  ~LockedImpl() = default;
66 
67  auto operator*() const -> U&
68  {
69  return *value;
70  }
71 
72  auto operator->() const -> U*
73  {
74  return value;
75  }
76 
77  /**
78  * Relinquish access to the data
79  *
80  * This prevents further access to the contained data through
81  * this handle, and allows other code to acquire access.
82  */
83  void drop()
84  {
85  value = nullptr;
86  lock.unlock();
87  }
88 
89  /**
90  * Allows waiting for a condition variable
91  *
92  * The protected data may be accessed both in the predicate and after this method completes.
93  */
94  template<typename Cv, typename Predicate>
95  void wait(Cv& cv, Predicate stop_waiting)
96  {
97  cv.wait(lock, stop_waiting);
98  }
99 
100  private:
101  friend class Synchronised;
102  LockedImpl(std::unique_lock<std::mutex>&& lock, U& value)
103  : value{&value},
104  lock{std::move(lock)}
105  {
106  }
107 
108  U* value;
109  std::unique_lock<std::mutex> lock;
110  };
111 
112  /**
113  * Smart-pointer-esque accessor for the protected data.
114  *
115  * Ensures exclusive access to the referenced data.
116  *
117  * \note Instances of Locked must not outlive the Synchronised
118  * they are derived from.
119  */
120  using Locked = LockedImpl<T>;
121  /**
122  * Lock the data and return an accessor.
123  *
124  * \return A smart-pointer-esque accessor for the contained data.
125  * While code has access to a live Locked instance it is
126  * guaranteed to have unique access to the contained data.
127  */
128  auto lock() -> Locked
129  {
130  return LockedImpl<T>{std::unique_lock{mutex}, value};
131  }
132 
133  /**
134  * Smart-pointer-esque accessor for the protected data.
135  *
136  * Provides const access to the protected data, with the guarantee
137  * that no changes to the data can be made while this handle
138  * is live.
139  *
140  * \note Instances of Locked must not outlive the Synchronised
141  * they are derived from.
142  */
143  using LockedView = LockedImpl<T const>;
144  /**
145  * Lock the data and return an accessor.
146  *
147  * \return A smart-pointer-esque accessor for the contained data.
148  * While code has access to a live Locked instance it is
149  * guaranteed to have unique access to the contained data.
150  */
151  auto lock() const -> LockedView
152  {
153  return LockedImpl<T const>{std::unique_lock{mutex}, value};
154  }
155 private:
156  std::mutex mutable mutex;
157  T value;
158 };
159 
160 }
161 
162 #endif //MIR_SYNCHRONISED_H_

Copyright © 2012-2023 Canonical Ltd.
Generated on Wed Feb 1 16:59:23 UTC 2023
This documentation is licensed under the GPL version 2 or 3.