132 lines
3.6 KiB
C++
132 lines
3.6 KiB
C++
/* @file value.h
|
|
concurrency helpers DiagStr, Guarded
|
|
*/
|
|
|
|
/**
|
|
* Copyright (C) 2008 10gen Inc.
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU Affero General Public License, version 3,
|
|
* as published by the Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,b
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU Affero General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Affero General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include "mutex.h"
|
|
#include "spin_lock.h"
|
|
|
|
namespace mongo {
|
|
|
|
/** declare that a variable that is "guarded" by a mutex.
|
|
|
|
The decl documents the rule. For example "counta and countb are guarded by xyzMutex":
|
|
|
|
Guarded<int, xyzMutex> counta;
|
|
Guarded<int, xyzMutex> countb;
|
|
|
|
Upon use, specify the scoped_lock object. This makes it hard for someone
|
|
later to forget to be in the lock. Check is made that it is the right lock in _DEBUG
|
|
builds at runtime.
|
|
*/
|
|
template <typename T, mutex& BY>
|
|
class Guarded : boost::noncopyable {
|
|
T _val;
|
|
public:
|
|
T& ref(const scoped_lock& lk) {
|
|
dassert( lk._mut == &BY );
|
|
return _val;
|
|
}
|
|
};
|
|
|
|
class DiagStr {
|
|
string _s;
|
|
mutable SpinLock m;
|
|
public:
|
|
DiagStr(const DiagStr& r) : _s(r.get()) { }
|
|
DiagStr() { }
|
|
bool empty() const {
|
|
scoped_spinlock lk(m);
|
|
return _s.empty();
|
|
}
|
|
string get() const {
|
|
scoped_spinlock lk(m);
|
|
return _s;
|
|
}
|
|
|
|
void set(const char *s) {
|
|
scoped_spinlock lk(m);
|
|
_s = s;
|
|
}
|
|
void set(const string& s) {
|
|
scoped_spinlock lk(m);
|
|
_s = s;
|
|
}
|
|
operator string() const { return get(); }
|
|
void operator=(const string& s) { set(s); }
|
|
void operator=(const DiagStr& rhs) {
|
|
scoped_spinlock lk(m);
|
|
_s = rhs.get();
|
|
}
|
|
};
|
|
|
|
#if 0 // not including in 2.0
|
|
|
|
/** Thread safe map.
|
|
Be careful not to use this too much or it could make things slow;
|
|
if not a hot code path no problem.
|
|
|
|
Examples:
|
|
|
|
mapsf<int,int> mp;
|
|
|
|
int x = mp.get();
|
|
|
|
map<int,int> two;
|
|
mp.swap(two);
|
|
|
|
{
|
|
mapsf<int,int>::ref r(mp);
|
|
r[9] = 1;
|
|
map<int,int>::iterator i = r.r.begin();
|
|
}
|
|
|
|
*/
|
|
template< class K, class V >
|
|
struct mapsf : boost::noncopyable {
|
|
SimpleMutex m;
|
|
map<K,V> val;
|
|
friend struct ref;
|
|
public:
|
|
mapsf() : m("mapsf") { }
|
|
void swap(map<K,V>& rhs) {
|
|
SimpleMutex::scoped_lock lk(m);
|
|
val.swap(rhs);
|
|
}
|
|
// safe as we pass by value:
|
|
V get(K k) {
|
|
SimpleMutex::scoped_lock lk(m);
|
|
map<K,V>::iterator i = val.find(k);
|
|
if( i == val.end() )
|
|
return K();
|
|
return i->second;
|
|
}
|
|
// think about deadlocks when using ref. the other methods
|
|
// above will always be safe as they are "leaf" operations.
|
|
struct ref {
|
|
SimpleMutex::scoped_lock lk;
|
|
public:
|
|
map<K,V> const &r;
|
|
ref(mapsf<K,V> &m) : lk(m.m), r(m.val) { }
|
|
V& operator[](const K& k) { return r[k]; }
|
|
};
|
|
};
|
|
#endif
|
|
}
|