Skip to content

Commit

Permalink
ThreadSafeRegistry is now fully thread-safe
Browse files Browse the repository at this point in the history
-Removed all the interfaces which provided direct internal access
 to the container and therefore were not thread-safe
-Protected all remaining interfaces with the mutex
-Made the mutex a member variable to avoid creating one each time
 the .icc file is included.
  • Loading branch information
Dr15Jones committed Jul 24, 2014
1 parent 8fcc292 commit 8555326
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 137 deletions.
123 changes: 33 additions & 90 deletions FWCore/Utilities/interface/ThreadSafeRegistry.h
Expand Up @@ -4,6 +4,7 @@
#include <map>
#include <vector>
#include <ostream>
#include <mutex>

// ----------------------------------------------------------------------

Expand All @@ -28,19 +29,15 @@
#pragma GCC visibility push(default)
namespace edm {
namespace detail {
struct empty { };

template <typename KEY, typename T, typename E=empty>
template <typename KEY, typename T>
class ThreadSafeRegistry {
public:
typedef KEY key_type;
typedef T value_type;
typedef E extra_type;
typedef typename std::map<key_type, value_type> collection_type;
typedef typename collection_type::size_type size_type;

typedef typename collection_type::const_iterator const_iterator;

typedef typename std::vector<value_type> vector_type;

static ThreadSafeRegistry* instance();
Expand Down Expand Up @@ -80,142 +77,88 @@ namespace edm {
/// Return the number of contained value_type objects.
size_type size() const;

/// Allow iteration through the contents of the registry. Only
/// const access is provided to the entries of the registry.
const_iterator begin() const;
const_iterator end() const;

/// Print the contents of this registry to the given ostream.
void print(std::ostream& os) const;

/// Provide access to the contained collection
collection_type& dataForUpdate();
collection_type const& data() const;

/// Provide access to the appendage "extra". The
/// ThreadSafeRegistry doesn't know what this is for, but
/// instantiations of the template can use it.
extra_type& extraForUpdate();
extra_type const& extra() const;

private:
ThreadSafeRegistry();
~ThreadSafeRegistry();

// The following two are not implemented.
ThreadSafeRegistry(ThreadSafeRegistry<KEY,T,E> const&);
ThreadSafeRegistry(ThreadSafeRegistry<KEY,T> const&);

ThreadSafeRegistry<KEY,T,E>&
operator= (ThreadSafeRegistry<KEY,T,E> const&);
ThreadSafeRegistry<KEY,T>&
operator= (ThreadSafeRegistry<KEY,T> const&);

mutable std::mutex mutex_;
collection_type data_;
extra_type extra_;
};

template <typename KEY, typename T, typename E>
inline
std::ostream&
operator<< (std::ostream& os, ThreadSafeRegistry<KEY,T,E> const& reg) {
operator<< (std::ostream& os, ThreadSafeRegistry<KEY,T> const& reg) {
reg.print(os);
return os;
}

template <typename KEY, typename T, typename E>
template <typename KEY, typename T>
void
ThreadSafeRegistry<KEY,T,E>::insertCollection(collection_type const& c) {
for (typename collection_type::const_iterator it = c.begin(), itEnd = c.end(); it != itEnd; ++it) {
insertMapped(it->second);
ThreadSafeRegistry<KEY,T>::insertCollection(collection_type const& c) {
for (auto const& item: c ) {
insertMapped(item.second);
}
}

template <typename KEY, typename T, typename E>
template <typename KEY, typename T>
void
ThreadSafeRegistry<KEY,T,E>::insertCollection(vector_type const& c) {
for (typename vector_type::const_iterator it = c.begin(), itEnd = c.end(); it != itEnd; ++it) {
insertMapped(*it);
ThreadSafeRegistry<KEY,T>::insertCollection(vector_type const& c) {
for (auto const& item: c) {
insertMapped(item);
}
}

template <typename KEY, typename T, typename E>
template <typename KEY, typename T>
inline
bool
ThreadSafeRegistry<KEY,T,E>::empty() const {
ThreadSafeRegistry<KEY,T>::empty() const {
std::lock_guard<std::mutex> guard(mutex_);
return data_.empty();
}

template <typename KEY, typename T, typename E>
template <typename KEY, typename T>
inline
bool
ThreadSafeRegistry<KEY,T,E>::notEmpty() const {
ThreadSafeRegistry<KEY,T>::notEmpty() const {
return !empty();
}

template <typename KEY, typename T, typename E>
template <typename KEY, typename T>
inline
typename ThreadSafeRegistry<KEY,T,E>::size_type
ThreadSafeRegistry<KEY,T,E>::size() const {
typename ThreadSafeRegistry<KEY,T>::size_type
ThreadSafeRegistry<KEY,T>::size() const {
std::lock_guard<std::mutex> guard(mutex_);
return data_.size();
}

template <typename KEY, typename T, typename E>
inline
typename ThreadSafeRegistry<KEY,T,E>::const_iterator
ThreadSafeRegistry<KEY,T,E>::begin() const {
return data_.begin();
}

template <typename KEY, typename T, typename E>
inline
typename ThreadSafeRegistry<KEY,T,E>::const_iterator
ThreadSafeRegistry<KEY,T,E>::end() const {
return data_.end();
}

template <typename KEY, typename T, typename E>
template <typename KEY, typename T>
void
ThreadSafeRegistry<KEY,T,E>::print(std::ostream& os) const {
ThreadSafeRegistry<KEY,T>::print(std::ostream& os) const {
std::lock_guard<std::mutex> guard(mutex_);
os << "Registry with " << size() << " entries\n";
for (const_iterator i=begin(), e=end(); i!=e; ++i) {
os << i->first << " " << i->second << '\n';
for (auto const& item: data_) {
os << item.first << " " << item.second << '\n';
}
}

template <typename KEY, typename T, typename E>
inline
typename ThreadSafeRegistry<KEY,T,E>::collection_type&
ThreadSafeRegistry<KEY,T,E>::dataForUpdate() {
return data_;
}

template <typename KEY, typename T, typename E>
inline
typename ThreadSafeRegistry<KEY,T,E>::extra_type&
ThreadSafeRegistry<KEY,T,E>::extraForUpdate() {
return extra_;
}

template <typename KEY, typename T, typename E>
inline
typename ThreadSafeRegistry<KEY,T,E>::extra_type const&
ThreadSafeRegistry<KEY,T,E>::extra() const {
return extra_;
}

template <typename KEY, typename T, typename E>
inline
typename ThreadSafeRegistry<KEY,T,E>::collection_type const&
ThreadSafeRegistry<KEY,T,E>::data() const {
return data_;
}

template <typename KEY, typename T, typename E>
ThreadSafeRegistry<KEY,T,E>::ThreadSafeRegistry() :
template <typename KEY, typename T>
ThreadSafeRegistry<KEY,T>::ThreadSafeRegistry() :
data_()
{ }


template <typename KEY, typename T, typename E>
ThreadSafeRegistry<KEY,T,E>::~ThreadSafeRegistry()
template <typename KEY, typename T>
ThreadSafeRegistry<KEY,T>::~ThreadSafeRegistry()
{ }

} // namespace detail
Expand Down
46 changes: 22 additions & 24 deletions FWCore/Utilities/interface/ThreadSafeRegistry.icc
Expand Up @@ -6,52 +6,50 @@

namespace edm {
namespace detail {
[[edm::thread_safe]] extern static std::mutex registry_mutex;

// ----------------------------------------------------------------------
template <typename KEY, typename T, typename E>
ThreadSafeRegistry<KEY,T,E>*
ThreadSafeRegistry<KEY,T,E>::instance() {
static ThreadSafeRegistry<KEY,T,E> me;
template <typename KEY, typename T>
ThreadSafeRegistry<KEY,T>*
ThreadSafeRegistry<KEY,T>::instance() {
static ThreadSafeRegistry<KEY,T> me;
return &me;
}

template <typename KEY, typename T, typename E>
template <typename KEY, typename T>
bool
ThreadSafeRegistry<KEY,T,E>::getMapped(key_type const& k, value_type& result) const {
ThreadSafeRegistry<KEY,T>::getMapped(key_type const& k, value_type& result) const {
bool found;
const_iterator i;
typename collection_type::const_iterator i;
{
// This scope limits the lifetime of the lock to the shorted
// required interval.
std::lock_guard lock(registry_mutex);
std::lock_guard<std::mutex> lock(mutex_);
i = data_.find(k);
found = (i != data_.end());
}
if (found) result = i->second;
return found;
}

template <typename KEY, typename T, typename E>
typename ThreadSafeRegistry<KEY,T,E>::value_type const*
ThreadSafeRegistry<KEY,T,E>::getMapped(key_type const& k) const {
template <typename KEY, typename T>
typename ThreadSafeRegistry<KEY,T>::value_type const*
ThreadSafeRegistry<KEY,T>::getMapped(key_type const& k) const {
bool found;
const_iterator i;
typename collection_type::const_iterator i;
{
// This scope limits the lifetime of the lock to the shorted
// required interval.
std::lock_guard lock(registry_mutex);
std::lock_guard<std::mutex> lock(mutex_);
i = data_.find(k);
found = (i != data_.end());
}
return found ? &(i->second) : static_cast<value_type const*> (0);
return found ? &(i->second) : static_cast<value_type const*> (nullptr);
}

template <typename KEY, typename T, typename E>
template <typename KEY, typename T>
bool
ThreadSafeRegistry<KEY,T,E>::insertMapped(value_type const& v) {
ThreadSafeRegistry<KEY,T>::insertMapped(value_type const& v) {
bool newly_added = false;
std::lock_guard lock(registry_mutex);
std::lock_guard<std::mutex> lock(mutex_);

key_type id = v.id();
if (data_.find(id) == data_.end()) {
Expand All @@ -69,11 +67,11 @@ namespace edm {
// in plugins.
#define DEFINE_THREAD_SAFE_REGISTRY_INSTANCE(X) \
namespace edm { namespace detail { \
template ThreadSafeRegistry<X::key_type,X::value_type,X::extra_type> *\
ThreadSafeRegistry<X::key_type,X::value_type,X::extra_type>::instance(); \
template bool ThreadSafeRegistry<X::key_type,X::value_type,X::extra_type>::getMapped(X::key_type const &, X::value_type &) const;\
template X::value_type const *ThreadSafeRegistry<X::key_type,X::value_type,X::extra_type>::getMapped(X::key_type const &) const;\
template bool ThreadSafeRegistry<X::key_type,X::value_type,X::extra_type>::insertMapped(X::value_type const &); \
template ThreadSafeRegistry<X::key_type,X::value_type> *\
ThreadSafeRegistry<X::key_type,X::value_type>::instance(); \
template bool ThreadSafeRegistry<X::key_type,X::value_type>::getMapped(X::key_type const &, X::value_type &) const;\
template X::value_type const *ThreadSafeRegistry<X::key_type,X::value_type>::getMapped(X::key_type const &) const;\
template bool ThreadSafeRegistry<X::key_type,X::value_type>::insertMapped(X::value_type const &); \
}}

#endif // FWCore_Utilities_ThreadSafeRegistry_icc
23 changes: 0 additions & 23 deletions FWCore/Utilities/src/ThreadSafeRegistry.cc

This file was deleted.

0 comments on commit 8555326

Please sign in to comment.