P
hustbaer schrieb:
würde mich interessieren warum du das getrennt halten willst.
also mein erstes beispiel war nur schnell zusammengecoded. ich wollte nur das wesentliche rüberbringen... naja...
ich poste mal den code, so wie er aussehen soll um dir mein konzept zu verdeutlichen. der code sollte auch mit jedem compiler funktionieren (hoffe ich... ich bin schon voll in c++0x, sorry)
die Guard klasse ist eigendlich nur ein wapper um einen mutex mit der man die eigendlichen "lock guards" erzeugt
ich hoffe, dass es nicht zu viel ist:
#include <iostream>
#include <list>
namespace Private
{
template<class T, class TGuard>
class Proxy
{
template<class U, class V> friend class SafeUsage;
Proxy(TGuard& m, T& v):
mGuard(m), mVariable(v) { mGuard.lock(); }
Proxy(const Proxy& p):
mVariable(p.mVariable), mGuard(p.mGuard) { }
public:
~Proxy() { mGuard.unlock(); }
T* operator->() { return &mVariable; }
template<class U>
void operator = (const U& val) { mVariable = val; }
private:
T& mVariable;
TGuard& mGuard;
};
template<class T, class TGuard>
class Proxy<const T,TGuard>
{
template<class U, class V> friend class SafeUsage;
Proxy(TGuard& m, const T& v):
mGuard(m), mVariable(v) { mGuard.lock(); }
Proxy(const Proxy& p):
mVariable(p.mVariable), mGuard(p.mGuard) { }
public:
~Proxy() { mGuard.unlock(); }
const T* operator->() const { return &mVariable; }
template<class U>
void operator = (const U& val) const { mVariable = val; }
private:
const T& mVariable;
TGuard& mGuard;
};
}
template<class T, class TGuard>
class SafeUsage
{
template<class U>
friend class Guard;
SafeUsage(TGuard& m, T& v):
mGuard(m), mVariable(v) { }
public:
Private::Proxy<T ,TGuard> operator->() { return Private::Proxy<T ,TGuard>(mGuard, mVariable); }
Private::Proxy<const T,TGuard> operator->() const { return Private::Proxy<const T,TGuard>(mGuard, mVariable); }
Private::Proxy<T ,TGuard> operator *() { return Private::Proxy<T ,TGuard>(mGuard, mVariable); }
Private::Proxy<const T,TGuard> operator *() const { return Private::Proxy<const T,TGuard>(mGuard, mVariable); }
private:
T& mVariable;
TGuard& mGuard;
};
template<class T, class TGuard>
class SafeScope
{
template<class U>
friend class Guard;
SafeScope(TGuard& m, T& v):
mGuard(m), mVariable(v) { mGuard.lock(); }
public:
~SafeScope() { mGuard.unlock(); }
T* operator->() { return &mVariable; }
const T* operator->() const { return &mVariable; }
T& operator* () { return mVariable; }
const T& operator* () const { return mVariable; }
private:
TGuard& mGuard;
T& mVariable;
};
template<class TMutex>
class Guard // ich könnte eigendlich auch gleich von TMutex ableiten... however
{
public:
void lock () { mMutex.lock(); }
void unlock() { mMutex.unlock(); }
template<class T>
SafeScope<T,Guard> protectInsideScope(T& var) { return SafeScope<T,Guard>(*this, var); }
template<class T>
SafeUsage<T,Guard> protectUsageOf(T& var) { return SafeUsage<T,Guard>(*this, var); }
private:
TMutex mMutex;
};
struct RecursiveMutexDummy
{
RecursiveMutexDummy(): counter(0) { }
void lock () { std::cout << "lock " << ++counter << std::endl; }
void unlock() { std::cout << "unlock " << counter-- << std::endl; }
int counter;
};
int main()
{
typedef Guard<RecursiveMutexDummy> Guardian;
typedef std::list<int> NumberList;
Guardian guardian;
NumberList numbers;
for(int i=0; i<5; i++)
numbers.push_back(i);
// protect whole scope
{
SafeScope<NumberList,Guardian> guardedNumbers = guardian.protectInsideScope(numbers);
for(NumberList::iterator i=guardedNumbers->begin(); i!=guardedNumbers->end(); i++)
std::cout << *i << std::endl;
}
// protect only usage
{
SafeUsage<NumberList,Guardian> guardedNumbers = guardian.protectUsageOf(numbers);
while(guardedNumbers->size())
{
std::cout << guardedNumbers->front() << std::endl;
guardedNumbers->pop_front();
}
}
return 0;
}
bin offen für anregungen
nochmal zu der copy-constructor sache:
der code funktioniert so wie er jetzt ist mit dem g++ auch mit -O0 (keine optimierung).
aber du hast recht, das könnte ein problem werden.
hier müsste noch gekärt werden, wie die richtige vorgehensweise ist.
[edit] ahhh... ok, habs jetzt erst geschnallt . ich könnte die Proxy und SafeScope klassen wie einen auto_ptr implementieren. dann würde immer die richtige anzahl an unlocks aufgrufen[/edit]
mfg
plassy