25#ifndef GOBY_MIDDLEWARE_TRANSPORT_DETAIL_SUBSCRIPTION_STORE_H
26#define GOBY_MIDDLEWARE_TRANSPORT_DETAIL_SUBSCRIPTION_STORE_H
28#include <condition_variable>
33#include <shared_mutex>
36#include <unordered_map>
52 using StoresMap = std::unordered_map<std::type_index, std::shared_ptr<SubscriptionStoreBase>>;
53 static std::unordered_map<std::thread::id, StoresMap> stores_;
54 static std::shared_timed_mutex stores_mutex_;
62 std::unique_ptr<std::unique_lock<std::mutex>>& lock)
68 std::shared_lock<std::shared_timed_mutex> stores_lock(stores_mutex_);
74 for (
auto const& s : stores) poll_items += s.second->poll(
thread_id, lock);
80 std::shared_lock<std::shared_timed_mutex> stores_lock(stores_mutex_);
83 for (
auto const& s : stores_.at(
thread_id)) s.second->unsubscribe_all_groups(
thread_id);
89 std::lock_guard<
decltype(stores_mutex_)> lock(stores_mutex_);
97 std::lock_guard<
decltype(stores_mutex_)> lock(stores_mutex_);
100 stores_.insert(std::make_pair(
thread_id, StoresMap()));
102 auto index = std::type_index(
typeid(StoreType));
105 std::make_pair(index, std::shared_ptr<StoreType>(
new StoreType)));
110 std::unique_ptr<std::unique_lock<std::mutex>>& lock) = 0;
116 DataProtection(std::shared_ptr<std::mutex> dm, std::shared_ptr<std::condition_variable> pcv,
117 std::shared_ptr<std::mutex> pm)
132 std::thread::id
thread_id, std::shared_ptr<std::mutex> data_mutex,
133 std::shared_ptr<std::condition_variable> cv,
134 std::shared_ptr<std::mutex> poller_mutex)
137 std::lock_guard<std::shared_timed_mutex> lock(subscription_mutex_);
141 subscription_callbacks_.insert(std::make_pair(
thread_id, Callback(
group, func)));
143 subscription_groups_.insert(std::make_pair(
group, it));
147 if (queue_it == data_.end())
149 auto bool_it_pair = data_.insert(std::make_pair(
thread_id, DataQueue()));
150 queue_it = bool_it_pair.first;
152 queue_it->second.create(
group);
156 data_protection_.insert(std::make_pair(
167 std::lock_guard<std::shared_timed_mutex> lock(subscription_mutex_);
170 auto range = subscription_groups_.equal_range(
group);
171 for (
auto it = range.first; it != range.second;)
173 auto sub_thread_id = it->second->first;
177 subscription_callbacks_.erase(it->second);
178 it = subscription_groups_.erase(it);
188 queue_it->second.remove(
group);
197 std::vector<detail::DataProtection> cv_to_notify;
199 std::shared_lock<std::shared_timed_mutex> lock(subscription_mutex_);
201 auto range = subscription_groups_.equal_range(
group);
202 for (
auto it = range.first; it != range.second; ++it)
204 std::thread::id
thread_id = it->second->first;
210 std::unique_lock<std::mutex> lock(*(data_protection_.at(
thread_id).data_mutex));
212 queue_it->second.insert(
group, data);
213 cv_to_notify.push_back(data_protection_.at(
thread_id));
219 for (
const auto& data_protection : cv_to_notify)
226 std::lock_guard<std::mutex> l(*data_protection.poller_mutex);
228 data_protection.poller_cv->notify_all();
234 std::unique_ptr<std::unique_lock<std::mutex>>& lock)
override
236 std::vector<std::pair<std::shared_ptr<typename Callback::CallbackType>,
237 std::shared_ptr<const Data>>>
239 int poll_items_count = 0;
245 if (queue_it ==
data_.end())
248 std::unique_lock<std::mutex> data_lock(
252 for (
auto data_it = queue_it->second.cbegin(),
end = queue_it->second.cend();
253 data_it !=
end; ++data_it)
258 for (
auto group_it = group_range.first; group_it != group_range.second; ++group_it)
260 if (group_it->second->first !=
thread_id)
264 for (
auto& datum : data_it->second)
270 data_callbacks.push_back(
271 std::make_pair(group_it->second->second.callback, datum));
274 queue_it->second.clear(
group);
279 for (
const auto& callback_datum_pair : data_callbacks)
280 (*callback_datum_pair.first)(std::move(callback_datum_pair.second));
282 return poll_items_count;
285 void unsubscribe_all_groups(std::thread::id
thread_id)
override
288 std::lock_guard<std::shared_timed_mutex>
lock(subscription_mutex_);
290 for (
auto it = subscription_groups_.begin(); it != subscription_groups_.end();)
292 auto sub_thread_id = it->second->first;
296 subscription_callbacks_.erase(it->second);
297 it = subscription_groups_.erase(it);
313 using CallbackType = std::function<void(std::shared_ptr<const Data>)>;
314 Callback(
const Group& g,
const std::function<
void(std::shared_ptr<const Data>)>& c)
315 : group(g), callback(new CallbackType(c))
319 std::shared_ptr<CallbackType> callback;
325 std::unordered_map<Group, std::vector<std::shared_ptr<const Data>>> data_;
328 void create(
const Group& g)
330 auto it = data_.find(g);
331 if (it == data_.end())
332 data_.insert(std::make_pair(g, std::vector<std::shared_ptr<const Data>>()));
334 void remove(
const Group& g) { data_.erase(g); }
336 void insert(
const Group& g, std::shared_ptr<const Data> datum)
338 data_.find(g)->second.push_back(datum);
340 void clear(
const Group& g) { data_.find(g)->second.clear(); }
341 bool empty() {
return data_.empty(); }
342 typename decltype(data_)::const_iterator cbegin() {
return data_.begin(); }
343 typename decltype(data_)::const_iterator cend() {
return data_.end(); }
347 static std::unordered_multimap<std::thread::id, Callback> subscription_callbacks_;
349 static std::unordered_multimap<Group,
350 typename decltype(subscription_callbacks_)::const_iterator>
351 subscription_groups_;
353 static std::unordered_map<std::thread::id, detail::DataProtection> data_protection_;
355 static std::shared_timed_mutex
359 static std::unordered_map<std::thread::id, DataQueue> data_;
362template <
typename Data>
363std::unordered_multimap<std::thread::id, typename SubscriptionStore<Data>::Callback>
364 SubscriptionStore<Data>::subscription_callbacks_;
365template <
typename Data>
366std::unordered_map<std::thread::id, typename SubscriptionStore<Data>::DataQueue>
367 SubscriptionStore<Data>::data_;
368template <
typename Data>
371 SubscriptionStore<Data>::subscription_callbacks_)::const_iterator>
372 SubscriptionStore<Data>::subscription_groups_;
373template <
typename Data>
374std::unordered_map<std::thread::id, detail::DataProtection>
375 SubscriptionStore<Data>::data_protection_;
377template <
typename Data> std::shared_timed_mutex SubscriptionStore<Data>::subscription_mutex_;
Class for grouping publications in the Goby middleware. Analogous to "topics" in ROS,...
Class that holds additional metadata and callback functions related to a publication (and is optional...
const goby::middleware::protobuf::TransporterConfig & cfg() const
Returns the metadata configuration.
static void remove(std::thread::id thread_id)
virtual int poll(std::thread::id thread_id, std::unique_ptr< std::unique_lock< std::mutex > > &lock)=0
virtual void unsubscribe_all_groups(std::thread::id thread_id)=0
static void insert(std::thread::id thread_id)
static void unsubscribe_all(std::thread::id thread_id)
SubscriptionStoreBase()=default
static int poll_all(std::thread::id thread_id, std::unique_ptr< std::unique_lock< std::mutex > > &lock)
virtual ~SubscriptionStoreBase()=default
Storage class for a specific interthread subscription (and related data). Used by InterThreadTranspor...
static void subscribe(std::function< void(std::shared_ptr< const Data >)> func, const Group &group, std::thread::id thread_id, std::shared_ptr< std::mutex > data_mutex, std::shared_ptr< std::condition_variable > cv, std::shared_ptr< std::mutex > poller_mutex)
static void unsubscribe(const Group &group, std::thread::id thread_id)
static void publish(std::shared_ptr< const Data > data, const Group &group, const Publisher< Data > &publisher)
*brief create JSON pointer *sa reference_tokens end()
goby::util::logger::GroupSetter group(std::string n)
std::unordered_multimap< goby::middleware::Group, typename decltype(SubscriptionStore< Data >::subscription_callbacks_)::const_iterator > SubscriptionStore< Data >::subscription_groups_
std::shared_timed_mutex SubscriptionStore< Data >::subscription_mutex_
std::unordered_map< std::thread::id, detail::DataProtection > SubscriptionStore< Data >::data_protection_
std::unordered_map< std::thread::id, typename SubscriptionStore< Data >::DataQueue > SubscriptionStore< Data >::data_
Objects implementing the Goby nested middleware.
std::string thread_id(std::thread::id i=std::this_thread::get_id())
The global namespace for the Goby project.
DataProtection(std::shared_ptr< std::mutex > dm, std::shared_ptr< std::condition_variable > pcv, std::shared_ptr< std::mutex > pm)
std::shared_ptr< std::mutex > data_mutex
std::shared_ptr< std::mutex > poller_mutex
std::shared_ptr< std::condition_variable > poller_cv