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 #include <boost/variant.hpp>
14 
15 #include <condition_variable>
16 #include <exception>
17 #include <map>
18 #include <mutex>
19 
20 namespace carla {
21 
22 namespace detail {
23 
24  class SharedException;
25 
26 } // namespace detail
27 
28  // ===========================================================================
29  // -- RecurrentSharedFuture --------------------------------------------------
30  // ===========================================================================
31 
32  /// This class is meant to be used similar to a shared future, but the value
33  /// can be set any number of times.
34  template <typename T>
36  public:
37 
39 
40  /// Wait until the next value is set. Any number of threads can be waiting
41  /// simultaneously.
42  ///
43  /// @return empty optional if the timeout is met.
44  boost::optional<T> WaitFor(time_duration timeout);
45 
46  /// Set the value and notify all waiting threads.
47  template <typename T2>
48  void SetValue(const T2 &value);
49 
50  /// Set a exception, this exception will be thrown on all the threads
51  /// waiting.
52  ///
53  /// @note The @a exception will be stored on a SharedException and thrown
54  /// as such.
55  template <typename ExceptionT>
56  void SetException(ExceptionT &&exception);
57 
58  private:
59 
60  std::mutex _mutex;
61 
62  std::condition_variable _cv;
63 
64  struct mapped_type {
66  boost::variant<SharedException, T> value;
67  };
68 
69  std::map<const char *, mapped_type> _map;
70  };
71 
72  // ===========================================================================
73  // -- RecurrentSharedFuture implementation -----------------------------------
74  // ===========================================================================
75 
76 namespace detail {
77 
78  static thread_local const char thread_tag{};
79 
80  class SharedException : public std::exception {
81  public:
82 
84  : _exception(std::make_shared<std::runtime_error>("uninitialized SharedException")) {}
85 
86  SharedException(std::shared_ptr<std::exception> e)
87  : _exception(std::move(e)) {}
88 
89  const char *what() const noexcept override {
90  return _exception->what();
91  }
92 
93  std::shared_ptr<std::exception> GetException() const {
94  return _exception;
95  }
96 
97  private:
98 
99  std::shared_ptr<std::exception> _exception;
100  };
101 
102 } // namespace detail
103 
104  template <typename T>
105  boost::optional<T> RecurrentSharedFuture<T>::WaitFor(time_duration timeout) {
106  std::unique_lock<std::mutex> lock(_mutex);
107  auto &r = _map[&detail::thread_tag];
108  r.should_wait = true;
109  if (!_cv.wait_for(lock, timeout.to_chrono(), [&]() { return !r.should_wait; })) {
110  return {};
111  }
112  if (r.value.which() == 0) {
113  throw_exception(boost::get<SharedException>(r.value));
114  }
115  return boost::get<T>(std::move(r.value));
116  }
117 
118  template <typename T>
119  template <typename T2>
120  void RecurrentSharedFuture<T>::SetValue(const T2 &value) {
121  std::lock_guard<std::mutex> lock(_mutex);
122  for (auto &pair : _map) {
123  pair.second.should_wait = false;
124  pair.second.value = value;
125  }
126  _cv.notify_all();
127  }
128 
129  template <typename T>
130  template <typename ExceptionT>
132  SetValue(SharedException(std::make_shared<ExceptionT>(std::forward<ExceptionT>(e))));
133  }
134 
135 } // 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:101
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:99
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...
boost::variant< SharedException, T > value
std::shared_ptr< std::exception > GetException() const
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