1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
|
// -*- 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>
#include <map>
namespace Moses
{
// todo: replace this with thread lock-free containers, if a stable library can
// be found somewhere
template<typename KEY, typename VAL, class CONTAINER = std::map<KEY,VAL> >
class
ThreadSafeContainer
{
protected:
mutable boost::shared_mutex m_lock;
CONTAINER m_container;
typedef typename CONTAINER::iterator iter_t;
typedef typename CONTAINER::const_iterator const_iter_t;
typedef typename CONTAINER::value_type entry_t;
public:
class locking_iterator
{
boost::unique_lock<boost::shared_mutex> m_lock;
CONTAINER 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 const* container,
const_iter_t 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_iter_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);
};
const_iter_t 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);
entry_t entry(key,val);
iter_t foo = m_container.insert(entry).first;
foo->second = val;
return foo->second;
}
VAL const*
get(KEY const& key, VAL const& default_val)
{
boost::unique_lock< boost::shared_mutex > lock(m_lock);
entry_t entry(key, default_val);
iter_t foo = m_container.insert(entry).first;
return &(foo->second);
}
VAL const*
get(KEY const& key) const
{
boost::shared_lock< boost::shared_mutex > lock(m_lock);
const_iter_t 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
|