Boost logo

Boost :

From: William Kempf (williamkempf_at_[hidden])
Date: 2001-08-29 11:37:53

From: "Peter Dimov" <pdimov_at_[hidden]>
>From: "William Kempf" <williamkempf_at_[hidden]>
>> >Fully compliant current() means that it produces a reference to a
>> >full-featured thread object, as if the thread has been created by the
>> >library.
>>Options #2 and #3 produce "fully compliant current()" by this definition.
>>OK, to be fair you're referring to the restriction on not being able to
>>"join" such objects, but I do not consider this to be as severe as you
>Exactly. There is one more thing to a 'fully compliant' current() - it has
>to return a reference to the same thread object (if the design exposes a
>thread object, of course) when invoked several times from the same thread -
>but I believe this is solvable.

This is a requirement from where? The only requirement is that the objects
encapsulate the same thread state (maybe you meant the state to be the
"thread object" you talk about exposing... but if that's the case we need to
be very careful with our terminology since we have a "thread object" that's
not the same thing as the "thread state").

>> >I don't quite understand. Why should a thread_ref use "wait"
>> >>semantics?
>> >I
>> >said, thread_ref join is exactly equivalent to boost::thread::join.
>>That's an implementation impossibility for "adopted" threads.
>I still don't understand.
>typedef shared_ptr<boost::thread> thread_ref;
>void join(thread_ref r)
> r->join();

This will fail (with undefined behavior) for "adopted" threads.

>What is impossible about it? join(thread_ref) has exactly the same
>as boost::thread::join, however it is defined. When boost::thread::join
>joins, so does thread_ref. When it waits, thread_ref waits too.

The difference is that boost::thread::join is never called for adopted
threads. You aren't making that distinction for thread_ref, and from a
usability standpoint it's going to be difficult to do so. That's why I
suggested using "join" semantics for threads created within the library and
"wait" semantics for threads that are adopted. Not the best solution, but a
fair compromise considering the problems.

>>For threads
>>that were not adopted you can give true "join" semantics, but this is true
>>for both POSIX and Boost.Threads base implementations for a thread_ref
>>concept. Now, once standardized it will be theoretically possible for
>>implementations to give true "join" semantics even for adopted threads
>>the implementations can take advantage of platform details that we do not
>>have access to in POSIX (and that's already the norm in Win32). But at
>>stage we're strictly talking about implementations based on top of POSIX
>>Win32 constructs, and it's simply not possible to create a thread_ref with
>>"join" semantics on top of POSIX.
>Perhaps you mean that a thread_ref returned by current() when called from
>adopted thread can't have "join" semantics, in which case I agree that this
>requires support from the pthreads implementation.

Where "join" is called is irrelevant. What's relevant is whether or not the
thread is adopted. Using psuedo code sine we don't have specific interfaces
to deal with here:

thread_ref ref = current(); // If the "current thread" wasn't created
                             // by the library we must adopt it here.
join(ref); // If we adopted it above we can't
                             // (safely) "join" here since it's nearly
                             // ensured to result in multiple "joins",
                             // once here and once by the code base
                             // we adopted the thread from.

>>Now, a valid decision would be to use "join" semantics for any thread
>>created by the library and "wait" semantics for those that are adopted. I
>>see only a few small holes in doing this, and they are not likely to be
>>issues for any actual uses. This is the route I'd go, and the
>>proposed design does not hinder you from doing this.
>Except for the default-constructed thread object validity across threads
>the main thread issue, yes.

This isn't an issue (or at least it's no different than implementing on top
of POSIX). You would use a cached (in TLS) boost::thread object for
thread's created within the library, which you can actually call "join" on
(and address the issue of multiple calls to "join" in any way you care to)
and for "adopted" threads your TLS state would contain both a default
constructed boost::thread object that you would never join and a "monitor"
that you'd wait on. The exact same thing would have to be done for POSIX
implementations. Now, once standardized actual implementers will have many
more (non-portable) options available to them that can eliminate all of
these issues.

The only grey area is your desire to treat the "initial thread" differently
from other "adopted" threads, but I'm not convinced that you should. A
POSIX implementation would allow you to, but would require some "hacks" that
would result in restrictions on when you can call current() within the
"initial thread".

>We are finally starting to understand each other. ;-) Although I have a
>feeling that we'll revisit most of this when additional functionality is

Probably. I've understood your issues from the beginning... it's mostly
been a problem with my conveying that the issues aren't a product of the
Boost.Threads (proposed) design but of portable constraints caused by
implementation on top of POSIX. I love the thread_ref concept in Win32
(though I'm convinced it's not the optimal C++ design), but for systems
(POSIX) that don't have this built in there are serious issues with using
full "join" semantics with "adopted" threads. If I were designing this
solely for acceptance by the C++ standard I'd be tempted to ignore these
issues, but Boost.Threads needs to be usable in a _portable_ manner even if
there's no language/abstract machine support. Given that, the thread_ref
implementation is going to be complicated and not have an optimal solution,
though it may have an acceptable one.

>Just to clarify: what does boost::thread::join() do when called on an
>adopted thread? What does it do when called a second time on a
>library-created thread? I tried to look at thread.html in the cvs but I
>think it's obsolete.

As of yesterday I checked in the proposed implementation, including the
documentation. The documentation was also posted to this list a week or so
ago when this thread started. But to answer the questions, calls to a
thread objects that are non-joinable (default constructed thread objects and
thread objects that have already been "joined") result in undefined
behavior, and is a programmatic error.

>>I've got two comments about this. First, Boost.Threads isn't a part of
>Yet. And if you (we) don't design it to be suitable for inclusion, it will
>never be.

It is suitable for inclusion. Some of the issues we've had to work around
become non-issues for the standard, though, and they can choose (and
probably should) to make adjustments for this fact. That's one of the
purposes for Boost.Threads... to help define the places that the abstract
machine needs modification. However, Boost.Threads should be usable with
out these modifications, so we will make some decisions based on issues like
this because of implementation concerns.

>>We have to make some decisions and choices that a standards
>>endorsed library would not, simply because they can accomodate such things
>>with changes to the abstract machine. The goal of Boost.Threads is to
>>document such areas with the hope that the standards committee can address
>>the abstract machine issues and change the library requirements
>I agree, however I don't see how the abstract machine affects the
>adoption/joining the main thread issue.

The creation of the main thread is a property of the abstract machine. We
can't make use of this quality since the current abstract machine makes no
mention of threads at all, and even the library extensions we're
implementing on top of give us no ability to distinguish the "initial
thread" from any other.

Bill Kempf

Get your FREE download of MSN Explorer at

Boost list run by bdawes at, gregod at, cpdaniel at, john at