Boost logo

Boost :

From: williamkempf_at_[hidden]
Date: 2001-07-31 16:56:56


--- In boost_at_y..., "Alexander Terekhov" <terekhov_at_d...> wrote:
>
> > > do you really want pthread_detach after each
> > > pthread_self() !? this is hardly what is needed
> > > here unless i am missing something big.
> >
> > Actually, this is a bug, but not probably for the reasons you
> > thought. Detaching every time is fine for the Boost.Threads
> > implementation, since we use a CV for join() instead of
pthread_join
> > ().
>
> well, in posix terminology you can detach (or join)
> the same thread only once:
>
> "The effect of multiple pthread_detach( ) calls on
> the same target thread is unspecified."

OK, I missed that. I thought multiple calls would just result in an
error, which could be safely ignored. In any event, this is
definately a bug and the call to pthread_detach() needs to be moved
to the constructor that creates a thread.

> "When a pthread_join () returns successfully, the target
> thread has been terminated. The results of multiple
> simultaneous calls to pthread_join ( ) specifying the
> same target thread are undefined."
>
> and i have yet to see/understand semantics of non-posix
> detach and join which would allow to do it multiple
> times. i would suggest that you choose different names
> if you really want to (and i doubt you can) go in non-posix
> direction..

It's a relatively common idiom on Win32 to "join" (WaitForSingleObject
(hThread)) a thread from multiple other threads. I also see no
reason to pick a different name here, as the name is descriptive of
what is being done.

> > The problem is, if the thread in question was not created by
> > Boost.Threads but by POSIX calls directly then this may yank the
rug
> > out from underneath someone. I'll have to fix this.
> >
> > > also,
> > > your DuplicateHandle/CloseHandle is really an
> > > overkill.. keeping just ONE handle and TLS/TSD
> > > key association is much more attractive/
> > > efficient, IMHO.
> >
> > Actually, the DuplicateHandle is required. It's the only way to
> > promote the pseudo-handle returned from GetCurrentThread() into a
> > real handle. The reason for using GetCurrentThread() instead of
TSD
> > is twofold. First, the TSD approach will chew up a TSD slot, and
if
> > we can avoid doing so we should, since TSD slots are limited to
64 to
> > begin with.
>
> that is not a problem if you are willing to implement ThreadLocal
class
> (see Java) which would keep the locals inside some thread's
container;
> member of thread class instance <- thread object.

Actually, I'm going that route with tss. However, there's still an
issue here with the implementation of the thread class. Many
programs make use of threads but don't (directly) use TSD. The TSD
slot for tss can be allocated only if the program makes use of it,
saving this one (precious) system TSD slot. If the thread class uses
tss, however, that one TSD slot is going to be stolen by the library
no matter what. It's a trade off, and since the
DuplicateHandle/CloseHandle approach requires little overhead I
prefer this solution. It's cleaner, in any event.
 
> > The more important reason, though, is that the TSD
> > approach will only work with threads created by Boost.Threads.
The
> > GetCurrentThread() approach safely adopts all threads into the
> > library.
>
> the real problem is the reclamation of dynamically created thread
> object (and destruction of its thread locals) attached to that
> "foreign" thread on win32 which does not have TSD destruction
> mechanism; but this is solvable.. well, sort of.. see pthreads-
win32.

I'm aware of how to solve TSD destruction on Win32. This isn't
really the issue. The DuplicateHandle/CloseHandle is *REQUIRED* to
allow the adoption of threads created outside of Boost.Threads. At
best we can optimize the runtime performance by doing this only once,
either at thread creation or at the first "self" creation, but this
is a very minor optimization with the drawbacks I've detailed here.
 
> > > why not "static thread& thread::current()" ?
> >
> > Because this would be difficult to implement. I could manage this
> > with TSD but that's a lot of overhead (actual heap allocations
would
> > be needed and clean up stacks used) for little benefit in the
> > interface.
>
> heap allocation is needed for detachable threads only;
> not for joinable.

No, heap allocations are required for threads created outside of
Boost.Threads at the very least with TSD. Also, there is no "detach"
in Boost.Threads, so that's irrelevant to the discussion.
 
> > Actually, on reflection, even TSD won't work here.
>
> i do not see any reasons why it won't work here (thread::current).
>
> > The thread object needs to exist beyond the lifetime
> > of the thread context.
>
> not necessarily; for joinable threads only.

No, for all threads. Imagine the following:

thread& thrd = thread::self();
// actual thread finishes between these instructions
if (thrd == thread::self())
   ...

The comparison instruction produces undefined behavior since thrd
references an object that's no longer in existence.

> > There is no way to safely implement this with a reference return.
>
> i do not follow you here.. thread::current() can only be called
> on the current thread context.

But the result can be passed to/used by other threads.

Bill Kempf


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