diff options
author | Ulrich Germann <Ulrich.Germann@gmail.com> | 2015-03-28 17:43:21 +0300 |
---|---|---|
committer | Ulrich Germann <Ulrich.Germann@gmail.com> | 2015-03-28 17:44:40 +0300 |
commit | a706569844ea38154d02c2607908842244f7a6b2 (patch) | |
tree | 1b1375b3ddd79d3ae088b42f84bf9393348821fe /moses | |
parent | 1b23edf62f4f390fc0d7c155d2b27158362f8f3d (diff) |
Thread-safe classes for storing context-specific information.
Diffstat (limited to 'moses')
-rw-r--r-- | moses/ContextScope.h | 57 | ||||
-rw-r--r-- | moses/thread_safe_container.h | 122 |
2 files changed, 179 insertions, 0 deletions
diff --git a/moses/ContextScope.h b/moses/ContextScope.h new file mode 100644 index 000000000..78940e575 --- /dev/null +++ b/moses/ContextScope.h @@ -0,0 +1,57 @@ +// -*- c++ -*- +// A class to store "local" information (such as task-specific caches). +// The idea is for each translation task to have a scope, which stores +// shared pointers to task-specific objects such as caches and priors. +// Since these objects are referenced via shared pointers, sopes can +// share information. + +#ifdef WITH_THREADS +#include <boost/thread/shared_mutex.hpp> +#include <boost/thread/locks.hpp> +#include <boost/foreach.hpp> +#endif + +#include "thread_safe_container.h" + +namespace Moses +{ + class ContextScope + { + protected: + typedef ThreadSafeContainer<void*,boost::shared_ptr<void> >scratchpad_t; + scratchpad_t m_scratchpad; + boost::shared_mutex m_lock; + public: + + template<typename T> + boost::shared_ptr<T> + get(T* key, bool CreateNewIfNecessary) const + { + using boost::shared_mutex; + boost::shared_pointer<void>* x; + { + boost::shared_lock<shared_mutex> lock(m_lock); + x = m_scratchpad.get(key); + if (x) return static_cast< boost::shared_pointer< T > >(*x); + } + boost::unique_lock<shared_mutex> lock(m_lock); + boost::shared_ptr<T> ret; + if (!CrateNewIfNecessary) return ret; + ret.reset(new T); + x = m_scratchpad.get(key, ret); + return static_cast< boost::shared_pointer< T > >(*x); + } + + ContextScope(ContextScope const& other) + { + boost::unique_lock<boost::shared_mutex> lock2(this->m_lock); + scratchpad_t::locking iterator m; + for (m = other.begin(); m != other.end(); ++m) + { + m_scratchpad.set(m->first, m->second); + } + } + + }; + +}; diff --git a/moses/thread_safe_container.h b/moses/thread_safe_container.h new file mode 100644 index 000000000..aca965373 --- /dev/null +++ b/moses/thread_safe_container.h @@ -0,0 +1,122 @@ +// -*- c++ -*- +#pragma once +#include "moses/Util.h" +#ifdef WITH_THREADS + +#include <time.h> +#include <boost/thread.hpp> +#include <boost/scoped_ptr.hpp> +#include <boost/shared_ptr.hpp> +#include <boost/weak_ptr.hpp> + +#include "moses/TargetPhrase.h" +#include <boost/thread/shared_mutex.hpp> +#include <boost/thread/locks.hpp> +#endif + +namespace Moses +{ + + // todo: replace this with thread lock-free containers, if a stable library can + // be found somewhere + + template<typename KEY, typename VAL, typename CONTAINER=map> + ThreadSafeContainer + { + protected: + mutable boost::shared_mutex m_lock; + CONTAINER<KEY,VAL> m_container; + typedef CONTAINER<KEY,VAL>::iterator iter_t; + typedef CONTAINER<KEY,VAL>::const_iterator const_iter_t; + typedef CONTAINER<KEY,VAL>::value_type entry_t; + public: + + class locking_iterator + { + boost::unique_lock<boost::shared_mutes> m_lock; + CONTAINER<KEY,VAL> const* m_container; + const_iter_t m_iter; + + locking_iterator(locking_iterator const& other); // no copies! + public: + locking_iterator() : m_container(NULL) { } + + locking_iterator(boost::shared_mutex& lock, + CONTAINER<KEY,VAL> const* container, + const_iter_ const& iter) + : m_lock(lock), m_container(container), m_iter(iter) + { } + + entry_t const& operator->() + { + UTIL_THROW_IF2(m_container == NULL, "This locking iterator is invalid " + << "or has not been assigned."); + return m_iter.operator->(); + } + + // locking operators transfer the lock upon assignment and become invalid + locking_iterator const& + operator=(locking_iterator& other) + { + m_lock.swap(other.m_lock); + m_iter = other.m_iter; + other.m_iter = other.m_container.end(); + } + + bool + operator==(const_itert_t const& other) + { + return m_iter == other; + } + + locking_iterator const& + operator++() { ++m_iter; return *this; } + + // DO NOT DEFINE THE POST-INCREMENT OPERATOR! + // locking_operators are non-copyable, + // so we can't simply make a copy before incrementing and return + // the copy after incrementing + locking_iterator const& + operator++(int); + }; + + CONTAINER<KEY,VAL>::const_iterator const& end() const + { return m_container.end(); } + + locking_iterator begin() const + { + return locking_iterator(m_lock, this, m_container.begin()); + } + + VAL const& set(KEY const& key, VAL const& val) + { + boost::unique_lock< boost::shared_mutex > lock(m_lock); + CONTAINER<KEY,VAL>::value_type entry(key,val); + iter foo = m_container.insert(entry).first; + return (foo->second = val); + } + + VAL const* get(KEY const& key, VAL const& default_val) + { + boost::shared_lock< boost::shared_mutex > lock(m_lock); + CONTAINER<KEY,VAL>::value_type entry(key,val); + pair<iter,bool> foo = m_container.insert(entry); + return &(foo->second); + } + + VAL const* get(KEY const& key) const + { + boost::shared_lock< boost::shared_mutex > lock(m_lock); + CONTAINER<KEY,VAL>::const_iterator m = m_container.find(key); + if (m == m_container.end()) return NULL; + return &m->second; + } + + size_t erase(Key const& key) + { + boost::unique_lock< boost::shared_mutex > lock(m_lock); + return m_container.erase(key); + } + }; +} +#endif |