CARLA
RecurrentSharedFuture.h
Go to the documentation of this file.
1 // Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
2 // de Barcelona (UAB).
3 //
4 // This work is licensed under the terms of the MIT license.
5 // For a copy, see <https://opensource.org/licenses/MIT>.
6 
7 #pragma once
8 
9 #include "carla/Exception.h"
10 #include "carla/Time.h"
11 
12 #include <boost/optional.hpp>
13 #ifdef _MSC_VER
14 #pragma warning(push)
15 #pragma warning(disable:4583)
16 #pragma warning(disable:4582)
17 #include <boost/variant2/variant.hpp>
18 #pragma warning(pop)
19 #else
20 #include <boost/variant2/variant.hpp>
21 #endif
22 
23 #include <condition_variable>
24 #include <exception>
25 #include <map>
26 #include <mutex>
27 
28 namespace carla {
29 
30 namespace detail {
31 
32  class SharedException;
33 
34 } // namespace detail
35 
36  // ===========================================================================
37  // -- RecurrentSharedFuture --------------------------------------------------
38  // ===========================================================================
39 
40  /// This class is meant to be used similar to a shared future, but the value
41  /// can be set any number of times.
42  template <typename T>
44  public:
45 
47 
48  /// Wait until the next value is set. Any number of threads can be waiting
49  /// simultaneously.
50  ///
51  /// @return empty optional if the timeout is met.
52  boost::optional<T> WaitFor(time_duration timeout);
53 
54  /// Set the value and notify all waiting threads.
55  template <typename T2>
56  void SetValue(const T2 &value);
57 
58  /// Set a exception, this exception will be thrown on all the threads
59  /// waiting.
60  ///
61  /// @note The @a exception will be stored on a SharedException and thrown
62  /// as such.
63  template <typename ExceptionT>
64  void SetException(ExceptionT &&exception);
65 
66  private:
67 
68  std::mutex _mutex;
69 
70  std::condition_variable _cv;
71 
72  struct mapped_type {
74  boost::variant2::variant<SharedException, T> value;
75  };
76 
77  std::map<const char *, mapped_type> _map;
78  };
79 
80  // ===========================================================================
81  // -- RecurrentSharedFuture implementation -----------------------------------
82  // ===========================================================================
83 
84 namespace detail {
85 
86  static thread_local const char thread_tag{};
87 
88  class SharedException : public std::exception {
89  public:
90 
92  : _exception(std::make_shared<std::runtime_error>("uninitialized SharedException")) {}
93 
94  SharedException(std::shared_ptr<std::exception> e)
95  : _exception(std::move(e)) {}
96 
97  const char *what() const noexcept override {
98  return _exception->what();
99  }
100 
101  std::shared_ptr<std::exception> GetException() const {
102  return _exception;
103  }
104 
105  private:
106 
107  std::shared_ptr<std::exception> _exception;
108  };
109 
110 } // namespace detail
111 
112  template <typename T>
113  boost::optional<T> RecurrentSharedFuture<T>::WaitFor(time_duration timeout) {
114  std::unique_lock<std::mutex> lock(_mutex);
115  auto &r = _map[&detail::thread_tag];
116  r.should_wait = true;
117  if (!_cv.wait_for(lock, timeout.to_chrono(), [&]() { return !r.should_wait; })) {
118  return {};
119  }
120  if (r.value.index() == 0) {
121  throw_exception(boost::variant2::get<SharedException>(r.value));
122  }
123  return boost::variant2::get<T>(std::move(r.value));
124  }
125 
126  template <typename T>
127  template <typename T2>
128  void RecurrentSharedFuture<T>::SetValue(const T2 &value) {
129  std::lock_guard<std::mutex> lock(_mutex);
130  for (auto &pair : _map) {
131  pair.second.should_wait = false;
132  pair.second.value = value;
133  }
134  _cv.notify_all();
135  }
136 
137  template <typename T>
138  template <typename ExceptionT>
140  SetValue(SharedException(std::make_shared<ExceptionT>(std::forward<ExceptionT>(e))));
141  }
142 
143 } // namespace carla
std::map< const char *, mapped_type > _map
void SetValue(const T2 &value)
Set the value and notify all waiting threads.
void throw_exception(const std::exception &e)
Definition: Carla.cpp:135
void SetException(ExceptionT &&exception)
Set a exception, this exception will be thrown on all the threads waiting.
This file contains definitions of common data structures used in traffic manager. ...
Definition: Carla.cpp:133
static thread_local const char thread_tag
const char * what() const noexcept override
This class is meant to be used similar to a shared future, but the value can be set any number of tim...
std::shared_ptr< std::exception > GetException() const
boost::variant2::variant< SharedException, T > value
Positive time duration up to milliseconds resolution.
Definition: Time.h:19
boost::optional< T > WaitFor(time_duration timeout)
Wait until the next value is set.
constexpr auto to_chrono() const
Definition: Time.h:50
SharedException(std::shared_ptr< std::exception > e)
std::shared_ptr< std::exception > _exception