// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma // de Barcelona (UAB). // // This work is licensed under the terms of the MIT license. // For a copy, see . #pragma once #include "carla/Exception.h" #include "carla/Time.h" #include #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable:4583) #pragma warning(disable:4582) #include #pragma warning(pop) #else #include #endif #include #include #include #include namespace carla { namespace detail { class SharedException; } // namespace detail // =========================================================================== // -- RecurrentSharedFuture -------------------------------------------------- // =========================================================================== /// This class is meant to be used similar to a shared future, but the value /// can be set any number of times. template class RecurrentSharedFuture { public: using SharedException = detail::SharedException; /// Wait until the next value is set. Any number of threads can be waiting /// simultaneously. /// /// @return empty optional if the timeout is met. boost::optional WaitFor(time_duration timeout); /// Set the value and notify all waiting threads. template void SetValue(const T2 &value); /// Set a exception, this exception will be thrown on all the threads /// waiting. /// /// @note The @a exception will be stored on a SharedException and thrown /// as such. template void SetException(ExceptionT &&exception); private: std::mutex _mutex; std::condition_variable _cv; struct mapped_type { bool should_wait; boost::variant2::variant value; }; std::map _map; }; // =========================================================================== // -- RecurrentSharedFuture implementation ----------------------------------- // =========================================================================== namespace detail { static thread_local const char thread_tag{}; class SharedException : public std::exception { public: SharedException() : _exception(std::make_shared("uninitialized SharedException")) {} SharedException(std::shared_ptr e) : _exception(std::move(e)) {} const char *what() const noexcept override { return _exception->what(); } std::shared_ptr GetException() const { return _exception; } private: std::shared_ptr _exception; }; } // namespace detail template boost::optional RecurrentSharedFuture::WaitFor(time_duration timeout) { std::unique_lock lock(_mutex); auto &r = _map[&detail::thread_tag]; r.should_wait = true; if (!_cv.wait_for(lock, timeout.to_chrono(), [&]() { return !r.should_wait; })) { return {}; } if (r.value.index() == 0) { throw_exception(boost::variant2::get(r.value)); } return boost::variant2::get(std::move(r.value)); } template template void RecurrentSharedFuture::SetValue(const T2 &value) { std::lock_guard lock(_mutex); for (auto &pair : _map) { pair.second.should_wait = false; pair.second.value = value; } _cv.notify_all(); } template template void RecurrentSharedFuture::SetException(ExceptionT &&e) { SetValue(SharedException(std::make_shared(std::forward(e)))); } } // namespace carla