From: William E. Kempf (wekempf_at_[hidden])
Date: 2003-03-26 15:31:46
David Brownell said:
>> The user can just call the method for every thread which uses
>> in a static library implementation. If a library ( LIB ) function uses
>> Boost.Threads internally, then it is up to the library function
>> to document this and iteratively define a function which can be called
>> calls the Boost.Threads function before the thread ends or, if the
>> library function itself controls the ending of the thread, it must do
>> it itself.
> As I have researched this topic, it has become quite clear that I am
> nowhere near an expert in this area, so forgive me if these questions
> are naive or have been hashed over before.
> Are these statements accurate: When a thread is created within a static
> lib, there is no way to find out when the thread has completed. In a
> DLL, DllMain is called when the thread is complete. This is important
> because TLS data must be destroyed when the thread is complete. In the
> current version of boost (1.30), TLS is a feature of the thread library,
> but not required. In future versions of boost, threads themselves will
> rely on TLS internally, so TLS is no longer a feature, but required.
> If a user must link with a static thread lib, a workaround would be for
> them to notify the thread library that the thread is about to complete,
> and any associated TLS data can be destroyed. This is not an optimum
> solution, as it places the onus on the user.
> Some questions: In the current thread library, can the associated TLS
> data be deleted before the thread is complete? In the next version of
> the library, can the associated TLS data be deleted before the thread is
Not sure I understand precisely what you're asking, but I'll make some
assumptions and say yes. However, read on.
> Would it be possible to add a level of indirection in the thread functor
> in static lib builds? For example, in a DLL build, the following
> happens (this is very loose, but should convey my meaning):
> --Thread Created (thread lib)
> -- User's thread functor (user code)
> --Thread Destroyed (thread lib)
> In a static lib build:
> -- Thread Created (thread lib)
> -- Internal thread functor (thread lib)
> -- User's thread functor (user code)
> -- Destroy TLS (thread lib)
> -- Thread Destroyed (thread lib)
> This would free the user from calling a destroy function at the end of
> the thread proc, but would enable static builds (if the above
> assumptions are correct).
This is the model used by MS. Threads are created at the low level by
calls to CreateThread. The C RTL uses some TLS, so if you call any C RTL
routines you're required to instead call _beginthread(ex), which creates a
proxy that ensures TLS data is cleaned up. Then MFC comes along and for
the same reasons requires you to instead call AfxBeginThread. One of the
more common errors that users make is to use the wrong thread creation
routine, which doesn't produce any obvious problems like a segfault.
Worse, this causes issues for people like me. Which thread creation
routine should Boost.Threads use? CreateThread is obviously a bad choice,
but the other routines are not so easy to choose between. If I use
AfxBeginThread(), the user is stuck with MFC, even if they don't use it.
If I use _beginthread(ex) (which is what I've chosen) then the user can't
safely call any MFC routines from threads created by Boost.Thread. If I
implement the solution you've given above, I cause these same issues on my
end users in triplicate.
More importantly Boost.Threads is meant to be useful for library
developers. Why should an application developer be forced to use
Boost.Threads just because library Foo choose to use Boost.Threads to make
the library thread safe?
This "solution" is fragile and difficult to manage today. Every time you
add yet another thread creation routine/proxy into the mix it gets
-- William E. Kempf
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk