Boost logo

Boost :

From: William Kempf (sirwillard_at_[hidden])
Date: 2000-12-04 16:44:36


--- In boost_at_[hidden], Kevlin Henney <kevlin_at_c...> wrote:
> In message <90gbnn+104i5_at_e...>, William Kempf <sirwillard_at_my-
> deja.com> writes
> >Think about a string that's shared
> >across threads.
>
> No, think of a string that's not shared across threads. As I said,
there
> are many subtleties to programming with threads and objects, and if
you
> are going to share mutable, sequential value types between threads
you
> have just fallen into one of them. Sorry, but that's just the way
it is
> :-(

Sharing data is a fundamental *need* of MT applications. You even go
so far as to illustrate this with your next argument here.
 
> This discussion does not simply apply to the function wrapper, it
is a
> multi-threading design consideration in general. Consider it for any
> type T that has non-atomic copying and assignment semantics. Using a
> common classification, we can treat objects as being passive (only
> execute when called, have no thread of their own) or active (having
> their own thread). There are different ways of classifying passive
> objects, but for the sake of argument here is the way that UML
> classifies operation synchronisation:
>
> sequential: Safe in a single thread only. Needs external locking to
be
> used across threads. This includes value objects, such as strings.
>
> guarded: Monitor-like and can be accessed across multiple threads.
> Synchronisation is self managed and access is serialised.
>
> concurrent: Multiple thread accesses without explicit locking are
> possible. This is the case with access to immutable data and for
lock-
> free change operations, eg InterlockedIncrement.

The shared string I mentioned fits category 1, sequential. The
problem is that external synchronization wasn't applied. It wasn't
applied because of a claim that the function_object wrapper was
thread safe internally so the programmer used it to wrap the string
figuring the library would take care of threading issues from there.
In other words, back to what I originally said, you can't gaurantee
thread safety unless the wrapped object is thread safe, which is
outside of the ability for the library to do.

> If T does not deep copy then it must refer to either immutable
objects
> or to objects with self-managed safety for the above examples to be
> safe. If T refers indirectly to something that does not satisfy
these,
> then the user of T must be responsible for its synchronisation. Deep
> copying objects that can be deep copied unasks the questions raised
by
> such issues.

A ref-counted idiom wrapping a thread safe object (i.e. the call to
operator() is gauranteed thread safe by the programmer) is just as
safe as a cloning idiom wrapping a thread safe object. If the object
is not gauranteed thread safe then deep copying has more points of
failure (cloning has both operator() call as well as copy operations,
while ref-counting only has one point of failure in operator()).
 
> >So, discussing thread safety as a reason to choose one over the
other
> >is a red herring, but if you insist going down that path it leads
to
> >ref-counting not cloning.
>
> Threading came up as a topic for discussion. I merely demonstrated
that
> both threading and the sequential value-based approach lead to the
same
> conclusion: cloning.

Which I disagree with. Since ref-counting reduces the points of
failure it would be preferred when thread safety is brought into the
picture. However, since neither can be gauranteed thread safe this
is a pointless argument to make. Threading makes no difference,
IMHO, on the choice here.

> When a design decision can be made for two
> different reasons this makes a very strong case for it and its
> stability. If you are still unhappy with the threading case, I
suggest
> we drop it and just focus on the one we can agree on.

That much sounds like a good idea at this point.

Bill Kempf


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