Boost logo

Boost :

From: William E. Kempf (williamkempf_at_[hidden])
Date: 2002-05-17 15:34:52


----- Original Message -----
From: "Eric D Crahen" <crahen_at_[hidden]>

> > This doesn't transfer ownership of a lock across scopes. It overlaps
> > locks on two different mutexes
>
> As far as the need to transfer ownership goes, I'm not entirely convinced
> there is a real need for this. The only use this seems to have is to
> create a wrapper that provides serialized access to each function on some
> object right?

No, I doubt that's the only need. It's just the most obvious real world use
case availabe to illustrate what's needed.

[snip]

> If you want to create a wrapper that would allow any arbitrary object to
> have some object level lock placed on it. Why not create a true wrapper
> for it, one that actually wraps the object rather than trying to
> distribute a wrapper among a set of pointers. Something like this,
>
> template <class T, class LockType>
> class GuardedObject : private NonCopyable {
>
> T* _object;
> LockType _lock;
>
> friend class Proxy;
> class Proxy : public Guard<T> {
>
> T* _ptr;
>
> Proxy(T* ptr, LockType& lock) : Guard<T>(lock), _ptr(ptr) {}
>
> T* operator->() {
> return _ptr;
> }
>
> }
>
> public:
>
> GuardedObject(T* object) : _object(object) {}
> ~GuardedObject() { delete _object; }
>
> Proxy operator->() {
> return Proxy(_object, _lock);
> }
>
> };
>
>
> {
> // Create a safe vector
> GuardedObject<vector<int> > safe_vector(new vector<int>());
>
> }
>
> The ownership issue dissappears and the lock lives just as long as the
> thing it guards. You can use auto_ptr, smart_ptrs or whatever is
> appropriate if you want to share this object.

Eric, your GuardedObject *IS* the same thing as the locking_ptr<> I've
referred you to. And your above implementation is flawed. Your Proxy
doesn't properly handle copy construction to use move semantics and the
result is that operator-> locks and unlocks the mutex twice. Technically
this won't cause any harm, but it's not efficient. Again, read Bjarne's
paper on this.

> > (where you use LockType Boost.Threads uses Mutex... locks are not
> > mutexes but are locks on a mutex).
>
> I look at a mutex as a kind of lock. Just like the lock on your door
> or a safe, you lock and unlock those things to control access to
> something. They're built up of other things that really do the
> locking and unlocking (tumbers in padlocks, or lower level synchonization
> primatives in mutexes) but they effectively endup acting as a lock, so I
> call em' that. Maybe its my OO nature :). Do most people see it that way,
> maybe its just me?

Actually, there was some criticism made by a few people for the names used
in Boost.Threads. However, what you call a Guard is an implementation of
the Scoped Locking pattern and thus IMHO better named as ScopedLock. So you
weren't incorrect in your terminology, it just didn't match the terminology
used in Boost.Threads and it's better that we use the same terminology in
this discussion.

> Also, I think there should be explict lock/unlock functions provided. Its
> enough to provide constructs like the ScopedPtr or Guards that make thier
> use optional. I'd rather not impose restrictions if they don't add
> anything to the functionality or thread model you want to use. It leaves
> things more flexible.

Again, this may well be what occurs in the end, but I want to explore
"safer" designs first. If those designs don't allow for efficient code in
all use cases then it will be time to place these operations in the public
interface.

Bill Kempf


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk