Boost logo

Boost :

From: Howard Hinnant (hinnant_at_[hidden])
Date: 2007-03-24 20:45:11


On Mar 24, 2007, at 7:00 PM, Emil Dotchevski wrote:

>
>> If it
>> prevents creating the "ideal" C++ interface (which, IMHO, is
>> something
>> along the lines of Howard's non-copyable thread class), then I'd
>> consider it a disadvantage.
>
> If someone can show that to be the case, I'd agree.
>
> (Off-topic to this argument, but in response to your opinion, I am
> not sure
> I see the benefits of non-copyable thread handles. I am also
> concerned about
> the fact that in N2184 there is no thread handle for the current
> thread,
> which means that code that manipulates the current thread needs to be
> special case. To me, this looks a lot like C++ without a this
> pointer. Good
> design is all about selectively limiting unnecessary flexibility,
> but I am
> not sure that having copyable thread handles is unnecessary.)

I've been trying to sit on my hands as much as possible, because I
really want to see independently formed ideas. But the hands slipped
out and here I go. :-)

Connection between pthreads and C++ threads: The critical connection
is cancellation. If you phthread_cancel a C++ thread, what happens?
If you thread::cancel() a pthreads thread, what happens? In the ideal
world everything would just work. I'm not convinced this is
practical. If fread() is currently cancelable (under pthreads) this
means fread() can now throw an exception in C++. This might be
upsetting to existing applications which assume the C fread() can't
throw an exception. Don't read into this that I think pthreads and C+
+ threads are inconsolable (I really don't know yet). Just read into
it that cancellation is the critical connection that needs to be put
under a microscope. I'm also not sure it is practical for some
existing C platforms to unwind C++ exceptions through C stack frames.

Benefit of non-copyable (but movable) thread handle: It is all in how
you view: join, detach and cancel. If these are considered non-const
operations on the thread, then the sole-ownership model is much
simpler. I've got a thread, I own it, nobody else does, I can do non-
const things with it without fear of disturbing the universe. If
join, detach and cancel are const operations, (and if all other things
you can do through the handle are const) then under-the-cover
reference semantics are benign.

This is quite analogous to reference counted strings: A reference
counted mutable string is complicated. If you modify one, you either
have to copy it so others sharing the data don't see the modification,
or you accept the fact that your string has reference semantics:
modify it here, and all other copies see what you've done. And OS
threads aren't copyable, so reference semantics for the handle are the
only option.

A reference counted immutable string is quite simple. You never
modify it. The fact that it is shared is virtually undetectable (an
implementation detail).

Current thread handle: This feeds from the sole ownership view vs the
shared ownership view. In the sole-ownership view (value semantics),
there is only one owner of a thread. Only the owner can do non-const
things with it. Even the thread does not own itself unless it has
been passed its own sole-ownership handle. This simplifies (imho)
reasoning about non-const operations on the thread. Otoh, if there is
a shared-ownership model (reference semantics), then one has copyable
thread handles and getting a copy of your own handle is very sensible.

Obviously there is some non-const functionality which "this thread"
should have access to: disabling exceptions is the poster child.
Even thread owners can't do this to their owned thread.

thread::id is a practical exception to this model. It is common to be
able to identify threads, especially to see if the last thread that
executed *here* is *me* (recursive mutex prime example). So
thread::id is copyable, and you can get a copy of your own
thread::id. One can only do const-things with a thread::id, making it
harmless to share (can't tell the difference between reference
semantics and value semantics).

In general: thread manipulation of yourself is neither specifically
allowed nor disallowed in N2184. There's a single owner to every
thread. If you want to manipulate that thread, you have to be the
owner, even if that thread is yourself. No special case. Although
joining with yourself could be considered hazardous to your health and
frowned upon by your universe as a whole. :-)

-Howard


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