Boost logo

Boost :

From: Trey Jackson (tjackson_at_[hidden])
Date: 2003-02-05 18:48:14


Peter Dimov wrote:
>The overhead is usually acceptable, even with a plain pthread_mutex.

Agreed. With that in mind, why wasn't the shared_ptr *also* protected
by a mutex?

>> Thereby making the simultaneous read/write safe (safe in that no
>> memory would be leaked b/c the pointers written/read).
>
>Consider this:
>
>// thread A
>
>p->f();
>
>// thread B
>
>p.reset();

As you pointed out, there's no way for that to be thread safe with the
shared_ptr, but it's probably not possible to make it safe with *any*
type of pointer. That's not what I was trying to ask.

You *could* make all reasonable operations on pointers thread safe
with a mutex. (where reasonable = all the examples shown on the
boost::shared_ptr documentation).

Why wasn't that done?

i.e.
if the reference count for a shared pointer is thread safe
in simultaneous write, why not make the pointer value thread safe as
well?

from boost docs:
,----------------
| boost::shared_ptr p, p3;
|
| // thread A
| p = p3; // reads p3, writes p
|
| // thread B
| p3.reset(); // writes p3, simultaneous read/write undefined
`----------------

you've already got the mutex "penalty" in the counter.
why not pull it out of there, put it in the shared pointer,
and then you've got thread safe pointers. right?

i understand that there's no guarantee on what p will point to, but
we know it's not going to point to garbage - but it *will* be p3 or 0.

>> Which brings me to a third question.
>> Let's say I've got a class (e.g. shared_count) that I sometimes want
>> to be protected by a mutex, and sometimes not. Say, for instance, I
>> want it to be protected by default, but sometimes I want to avoid that
>> overhead b/c I know I'll be using it in an environment that's already
>> protected by a mutex (and can avoid the extra mutex overhead).
>
>Can you demonstrate this with an example?

I may have this a little wrong, but here's my shot at an example:

today
-----
template <typename T> class shared_ptr;
  (which uses)
class counted_base;

tomorrow
--------
class counted_base<class LockingStrategy = MutexLockingStrategy>;

template <typename T, class LockingStrategy = MutexLockingStrategy> class shared_ptr;
  (which specializes)
counted_base<NullLockingStrategy>

(where MutexLockingStrategy and NullLockingStrategy are defined in the
previous email)

So, you use a template for the counted_base class to define the type
of thread locking primitives you want to use.

Today's counted_base == tomorrow's counted_base<MutexLockingSTrategy>
in terms of functionality.

But, the flexibility allows the shared_ptr to avoid the mutex inside
the shared_ptr;

I started thinking about this with my own work.
I've got a query-tree class (2-D binary tree) that sometimes needs to
be thread-safe, and sometimes not - in the same executable.

e.g. I want to be able to do:

QT unsafe_tree;

QT<MutexLockingStragegy> thread_safe_tree;

and this applies to all sorts of containers/classes.

>> Just wondering if the above strategy could be used in the case of
>> shared_count, and if not, why not?
>
>Because of the extra LockingStrategy parameter. :-)

Yeah, but is there a technical reason for not doing something like the
above?

I'm wondering what the downside would be?

The upsides I can see are:

1) pulls mutex details outside of the class
2) gets rid of ugly '#ifdef BOOST_HAS_THREADS' lines
3) allows different specializations of the (counted_base) class in the
   same binary

Obviously, the MutexLockingStrategy class would still have the ugly
#ifdef lines in it, but that's it.

TJ

-- 
Trey Jackson
tjackson_at_[hidden]
"Instant gratification takes too long."
-- Carrie Fisher

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