I'm aware boost has a support for read/writer locks however I'm wondering if it provides a class that wraps it on an object before I write my own or if there is some other way to protect a class safely.
boost read/writer https://stackoverflow.com/a/6450576/1335325
I'd like something like
class A
{
...
};
....
class B
{
....
ReadWriterLock<A> m_a; //Locked under read/write synchronization strategy.
};
...
how to use:
something like:
GetForRead<mutex> lock(m_a);
...
GetForWrite<mutex> lock(m_a);
etc....
Or if someone wants to try to write on that would be great also.
Cheers
Update here is my first go at it. I would be curious as to any suggestions for improvements.
template <class T>
class WriteOnceReadMany
{
public:
template <class T>
class LockedRead
{
public:
LockedRead(const T& data, boost::shared_mutex& mutex)
: m_lock(mutex)
, m_Data(&data)
{
}
LockedRead(WriteOnceReadMany& data)
: m_lock(data.m_access)
, m_Data(&data.m_Data)
{
}
operator const T&() const //Returns a copy so we cannot access the object while in use
{
return *m_Data;
}
const T& get() const //Returns a copy so we cannot access the object while in use
{
return *m_Data;
}
const T* operator->() const
{
return m_Data;
}
private:
boost::shared_lock<boost::shared_mutex> m_lock;
const T* m_Data;
};
template <class T>
class LockedWrite
{
public:
LockedWrite(T& data, boost::shared_mutex& mutex)
: m_lock(mutex)
, m_Data(&data)
{
}
LockedWrite(WriteOnceReadMany& data)
: m_lock(data.m_access)
, m_Data(&data.m_Data)
{
}
LockedWrite& operator=(T const& newval)
{
value = newval;
return *this;
}
operator T&() //Returns a copy so we cannot access the object while in use
{
return *m_Data;
}
T& get() //Returns a copy so we cannot access the object while in use
{
return *m_Data;
}
T* operator->()
{
return m_Data;
}
private:
boost::upgrade_lock<boost::shared_mutex> m_lock;
T* m_Data;
};
typedef LockedRead<T> ReadLock;
typedef LockedWrite<T> WriteLock;
WriteOnceReadMany(const T& data)
: m_Data(data)
{
}
WriteOnceReadMany()
{
}
~WriteOnceReadMany()
{
boost::upgrade_lock<boost::shared_mutex> lock(m_access); //Make sure we can delete this object. Potential race conditions may still occur.
}
WriteOnceReadMany& operator=(T const& newval)
{
boost::upgrade_lock<boost::shared_mutex> lock(m_access);
m_Data = newval;
return *this;
}
operator const T() const //Returns a copy so we cannot access the object while in use
{
boost::shared_lock<boost::shared_mutex> lock(m_access);
return m_Data;
}
//These are provided to avoid copy costs. They allow you to hold on to the object for a longer period of time.
//Use with care and don't hold on to the lock for too long.
ReadLock read() const
{
return ReadLock(m_Data, m_access);
}
WriteLock write()
{
return WriteLock(m_Data, m_access);
}
private:
T m_Data;
mutable boost::shared_mutex m_access; //I really hate using mutable maybe there is a better way to keep constsness
};
Use example:
struct A
{
int x;
int y;
...
};
WriteOnceReadMany<A> m_a;
A copyOfA = m_a; //Read safe copy
m_a = copyOfA; //Write safe operation
WriteOnceReadMany<A>::ReadLock a_readonly(m_a); //Get as a reference for efficiency
const A& a = m_a.get(); //read only get (is const)
...
WriteOnceReadMany<A>::WriteLock a_readwrite(m_a); //Get as a reference for efficiency
A& a = m_a.get(); //write
...