Boost logo

Boost :

From: Peter Dimov (pdimov_at_[hidden])
Date: 2003-02-06 07:36:49


Trey Jackson wrote:
> 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?

Because that would be two mutexes instead of one, which directly translates
to twice as much time overhead + per-pointer size overhead for the
additional mutex, all that for questionable benefits.

> 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).

Have you tried? ;-)

> 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?

See above. Per-pointer mutex, questionable value.

> 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?

Nope. You still need the counter mutex penalty. See example 2, that modifies
two different shared_ptr instances, with well defined results. Those two
instances can well share a count.

Furthermore, even if the above were defined, why would you want to do that?
The value of p would be unspecified, depending on what thread got there
first.

> 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.

Yep. But a well designed program doesn't need this construct. The extra
overhead would only "help" badly designed programs, but everyone will have
to pay.

> 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.

Yes, this is a reasonable design. It's a tradeoff between safety and
performance. You assert that you'll never, ever, share unsafe_tree between
threads.

For container classes this is pretty easy to enforce. With shared_ptr things
are a bit more complicated since it often leads to designs where it's not
known in advance whether a particular shared_ptr instance is shared with
other parts of the program. It is typically a good idea to mentally track
ownership, but in some cases it's easier to just think locally, and not
bother with the big picture.

I'm pretty sure that there are programs where the unnecessary
synchronization overhead would be unacceptable. But these cases are much
rarer than one might think.

> >> 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?

Depends on what you mean by "a technical reason". It is very controversial
whether the cost of an extra template parameter can be considered a
technical reason. :-)

> 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

Actually the mutex details are already outside of the class. They are
encapsulated in lightweight_mutex. The ugly #ifdef lines are redundant, too.
You can remove them in your local copy, and things will still work. #ifdefs
are there only because some compilers can't optimize out the empty mutex,
and others can, but complain for unused variables and code with no effects.


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