Re: CMultiLock example
On Aug 19, 10:55 pm, "Doug Harrison [MVP]" <d...@mvps.org> wrote:
On Wed, 19 Aug 2009 16:39:32 -0400, Joseph M. Newcomer
<newco...@flounder.com> wrote:
I find it best to build something like
template <class T> class CLockedList : public CList<T> {
public:
void Add(T p) { EnterCriticalSection(&lock);
=
list.Add(p);
LeaveCriticalSection(&lock); }
void Remove(T p) { EnterCriticalSection(=
&lock);
p);
LeaveCriticalSection(&lock); }
CLockedList<T>() { InitializeCriticalSection(&lock); }
virtual ~CLockedList<T>() { DeleteCriticalSection(&lock); }
protected:
CList<T> list;
CRITICAL_SECTION lock;
};
The problem with that is always, "How do you lock around a series of
operations that must be atomic?" You can either expose the locking
mechanism or give up on making the class "inherently" thread-safe and
require users to impose locking entirely from the outside.
(Obligatory disclaimer: YMMV)
Third option: apply the interface segregation principle (http://
www.objectmentor.com/resources/articles/isp.pdf). That is, expose a
specific interface for said series of operations (also expose other
interfaces for other use-cases).
e.g.
struct WholeBunchAtOnce { virtual void DoIt(params) = 0; }
struct BasicOps { virtual void Op1()=0; /*etc*/ }
class ThreadSafe :
public WholeBunchAtOnce,
public /*protected?*/ BasicOps
{ /*implement all here, ye dawg!*/}
then
void UseCase1(WholeBunchAtOnce& me, params) {... me.DoIt(params)... }
void UseCase1(BasicOps& me, params) { ... me.Op1(params);...}
then
ThreadSafe Me;
UseCase1(Me, params);
and (in other code, hopefully far, far away)
UseCase2(me, otherParams);
Fourth option: for "grouped" operations, force clients to use a
"locked" proxy object, e.g.
class LockedRefToX
{
LockedRefToX(X& x) { LockX() }
~LockedRefToX() { UnlockX() }
X* operator->*()
};
(This requires e.g. that LockedRefToX is friend of X for Lock/Unlock).
Goran.