Re: Concurrent Containers
Scott Meyers <NeverRead@aristeia.com> wrote in
news:i5mi9d$3pk$1@news.albasani.net:
On 9/1/2010 2:34 PM, Paavo Helde wrote:
Yes, sometimes such containers are exactly what is needed. However,
given that one can in about 20 lines create a template class which is
able to wrap any non-concurrent class and expose a locking proxy
pointer for safe concurrent access, this is not so difficult to
achieve.
Can you elaborate on what you mean here? Suppose I want to take a
std::map or std::unordered_map (C++0x) and make it safe for multiple
threads to simultaneously perform insertions. What will a "locking
proxy pointer" do to enable this behavior?
Here is a simple scratch, this can be enhanced no doubt. It essentially
locks the whole container during the operation. As stressed by numerous
other replies, this locking scope is often either too narrow or too
broad, and as such this solution does not buy you much. However, it is
not expensive either. This is working in current C++, no C++0x required.
#include <boost/thread/mutex.hpp> // or any other mutex you like
// for demo
#include <set>
#include <iostream>
template<class T>
class Lockable {
public:
class LockedPtr {
public:
T* operator->() const {return &ref_;}
T& operator*() const {return ref_;}
private:
T& ref_;
boost::mutex::scoped_lock lk_;
friend class Lockable<T>;
LockedPtr(T& ref, boost::mutex& mx)
: ref_(ref)
, lk_(mx)
{}
};
LockedPtr Lock() {
return LockedPtr(x_, mx_);
}
private:
T x_;
boost::mutex mx_;
};
int main() {
Lockable< std::set<std::string> > myset;
myset.Lock()->insert("foo");
std::cout << "foo: " << myset.Lock()->count("foo") << "\n";
std::cout << "bar: " << myset.Lock()->count("bar") << "\n";
{
// an atomic 2-operation transaction:
Lockable< std::set<std::string> >::LockedPtr
lckptr = myset.Lock();
lckptr->erase("foo");
lckptr->insert("foo_ex");
}
// for simplicity, I create no other threads for actual
// MT access, but the idea should be clear.
};