
Dayton wrote: ...
I tend to think in the similar direction. Threads class happens to be the first one that I tried to use as a newcomer to boost++ so I ended up 'complaining' here. In particular, losing features that one learns to take for granted on some platforms (like thread stop, suspended start) is not motivating. Also, relying on OS notifications (like DLL_THREAD_DETACH on Win32) for TLS cleanup, and extra code required to support boost threads static library on Win32 is not my favourite, despite a rather ingenious implementation. I think it would be best if we can completely avoid using Win32 DLL process/thread notifications and make TLS cleanup part of the thread function object. I already expressed, somewhat radical I guess, opinion that, at least on Win32, TLS functionality is probably not worth the trouble of existing cleanup support code. Tony __________________________________ Do you Yahoo!? Yahoo! Mail Address AutoComplete - You start. We finish. http://promotions.yahoo.com/new_mail

Tonko Juricic wrote:
Dayton wrote: ...
I tend to think in the similar direction.
Threads class happens to be the first one that I tried to use as a newcomer to boost++ so I ended up 'complaining' here.
In particular, losing features that one learns to take for granted on some platforms (like thread stop, suspended start) is not motivating.
Boost.Threads is cross platform and, unfortunately, some features are hard to support on all platforms. Hopefully these ones can be provided in some fashion in the future, however.
Also, relying on OS notifications (like DLL_THREAD_DETACH on Win32) for TLS cleanup, and extra code required to support boost threads static library on Win32 is not my favourite, despite a rather ingenious implementation.
If you can think of a better way, we'd be glad to hear it.
I think it would be best if we can completely avoid using Win32 DLL process/thread notifications and make TLS cleanup part of the thread function object.
The next release will clean up TLS right after the thread function exits, but that doesn't work for threads that aren't created by Boost.Threads. If that's good enough for you, good! However, if you need TLS cleanup for threads not created by Boost.Threads, the DLL_THREAD_DETACH or some other approach is still necessary.
I already expressed, somewhat radical I guess, opinion that, at least on Win32, TLS functionality is probably not worth the trouble of existing cleanup support code.
If you don't use TLS cleanup, you don't need the cleanup support. Mike

On Tue, 27 Jul 2004 22:23:21 -0400 Michael Glassford <glassfordm@hotmail.com> wrote:
The next release will clean up TLS right after the thread function exits, but that doesn't work for threads that aren't created by Boost.Threads. If that's good enough for you, good! However, if you need TLS cleanup for threads not created by Boost.Threads, the DLL_THREAD_DETACH or some other approach is still necessary.
As I pointed out in another posting: DLL_THREAD_DETACH might already be too late for cleanup. You are relying on the fact that the c-runtime (with respect to this very thread) is still in a sane state! In fact it might not since the runtimes own detach functions already have been called at this time. (Happens within _endthread). So I think doing the cleanup after a boost thread has ended is very reasonable. Nevertheless I am currently trying to accomplish the very same functionality by transparently "hooking" _endthread to call the cleanup code. This way some of the orthogonality is given back, since it is most likely that other threads are based on _beginthread _endthread at minimum (These are required to work with the C-Run time). Going this way would only preclude using native threads, which I consider beeing a minor nuisance. Roland

Roland wrote:
You are relying on the fact that the c-runtime (with respect to this very thread) is still in a sane state! In fact it might not since the runtimes own detach functions already have been called at this time. (Happens within _endthread).
I saw your post and I think that's strong point *against* using thread local storage (as delivered by runtime and OS), and replace it with some structure. B.

Hello, is there any CVS branch dedicated for this threads rewrite? Thanks, Karel -- Karel Gardas kgardas@objectsecurity.com ObjectSecurity Ltd. http://www.objectsecurity.com

Karel Gardas wrote:
Hello,
is there any CVS branch dedicated for this threads rewrite?
The rewrite doesn't exist yet, and we're still hoping it may not need to. We are planning to redesign and rewrite portions of Boost.Threads, but would still very much like to avoid rewriting the whole library just for licensing reasons. Having said that, there is a thread_dev branch in CVS which currently contains Boost.Threads changes that William Kempf checked in before he stopped working on the library. I've been finishing his changes and moving them to the main branch, but haven't moved them all yet. Chances are that any rewrite will use this branch. Mike

Bronek Kozicki wrote:
Roland wrote:
You are relying on the fact that the c-runtime (with respect to this very thread) is still in a sane state! In fact it might not since the runtimes own detach functions already have been called at this time. (Happens within _endthread).
I saw your post and I think that's strong point *against* using thread local storage (as delivered by runtime and OS), and replace it with some structure.
Thread-local storage is to be used exactly in scenarios where such replacement is not possible.

Roland wrote:
DLL_THREAD_DETACH might already be too late for cleanup. You are relying on the fact that the c-runtime (with respect to this very thread) is still in a sane state! In fact it might not since the runtimes own detach functions
Hm? After some checking I can see that TLS can be freed after thread termination, see: http://msdn.microsoft.com/library/en-us/dllproc/base/thread_local_storage.as... What worries me is TlsFree documentation, saying "It is expected that DLLs call this function (if at all) only during DLL_PROCESS_DETACH.". Possibly I misunderstood your point ... B.

On Wed, 28 Jul 2004 11:12:34 +0200 Bronek Kozicki <brok@rubikon.pl> wrote:
Roland wrote:
DLL_THREAD_DETACH might already be too late for cleanup. You are relying on the fact that the c-runtime (with respect to this very thread) is still in a sane state! In fact it might not since the runtimes own detach functions
Hm? After some checking I can see that TLS can be freed after thread termination, see: http://msdn.microsoft.com/library/en-us/dllproc/base/thread_local_storage.as... What worries me is TlsFree documentation, saying "It is expected that DLLs call this function (if at all) only during DLL_PROCESS_DETACH.".
This is true, but the global object itself usually "lives" in an object, which you "normally" need to free by means of the delete operator which in turn relies on availability of the c-runtime. Have a look at the current implementation of the thread_specific_pointer which calls delete on the object to free the heap when the thread is done. Roland

This is true, but the global object itself usually "lives" in an object,
which you "normally"
need to free by means of the delete operator which in turn relies on availability of the c-runtime.
The C runtime should be available and in a sane state for all thread terminations except possibly the main thread right? So as long as we possibly do something special for the main thread we're surely OK. Certainly I've never seen your concerns in practice. What am I missing? John.

On Wed, 28 Jul 2004 11:12:42 +0100 John Maddock <john@johnmaddock.co.uk> wrote:
This is true, but the global object itself usually "lives" in an object,
which you "normally"
need to free by means of the delete operator which in turn relies on availability of the c-runtime.
The C runtime should be available and in a sane state for all thread terminations except possibly the main thread right? So as long as we possibly do something special for the main thread we're surely OK. Certainly I've never seen your concerns in practice. What am I missing?
It might not be of concern in practice, but as well it might. It is simply c-runtime implementation dependent. Some examples come to mind: 1) The MT-version of the library has some global variable such as e.g. the buffer for strbrk. Consequently you would not be allowed then to use this function in a destructor then. (Not a big deal, but....) 2) The MT-version of the c-runtime (at least MSVC) does some floating point init/deinit. How's about using floating point in a destructor? 3) Think of a debugging library that tracks memory allocation with respect to threads. You would need some means to access the "living" thread. How's about this? I simply think it is never good using something after it has gone, without the explicit notion that this is ok. And since the standard does not deal with threads explicitly one should be very careful I think. Some very nasty and hard to detect bugs might be the consequence. Roland

Roland wrote:
On Wed, 28 Jul 2004 11:12:42 +0100 John Maddock <john@johnmaddock.co.uk> wrote:
This is true, but the global object itself usually "lives" in an object,
which you "normally"
need to free by means of the delete operator which in turn relies on
availability of
the c-runtime.
The C runtime should be available and in a sane state for all thread terminations except possibly the main thread right? So as long as we possibly do something special for the main thread we're surely OK. Certainly I've never seen your concerns in practice. What am I missing?
It might not be of concern in practice, but as well it might. It is simply c-runtime implementation dependent.
Some examples come to mind: 1) The MT-version of the library has some global variable such as e.g. the buffer for strbrk. Consequently you would not be allowed then to use this function in a destructor then. (Not a big deal, but....) 2) The MT-version of the c-runtime (at least MSVC) does some floating point init/deinit. How's about using floating point in a destructor? 3) Think of a debugging library that tracks memory allocation with respect to threads. You would need some means to access the "living" thread. How's about this?
I simply think it is never good using something after it has gone, without the explicit notion that this is ok. And since the standard does not deal with threads explicitly one should be very careful I think. Some very nasty and hard to detect bugs might be the consequence.
I'm not sure if it's documented anywhere (if not, it would be bad to rely on it, of course), but the behavior I have observed is that if my dll depends on another dll, Windows calls the other dll's process-attach and thread-attach before mine and its thread-detach and process-detach after mine. If this is documented to be the case, doesn't that solve at least most of this problem? Mike

On Wed, 28 Jul 2004 08:40:46 +0200 Bronek Kozicki <brok@rubikon.pl> wrote:
Tonko Juricic wrote:
Also, relying on OS notifications (like DLL_THREAD_DETACH on Win32) for TLS cleanup, and extra
Maybe this could be replaceed with RegisterWaitForSingleObject (waiting for thread handle)?
This would increase the number of threads seriously, since you can only wait for a very limited number of objects in a call to WaitFor. Roland

Roland wrote:
This would increase the number of threads seriously, since you can only wait for a very limited number of objects in a call to WaitFor.
AFAIK RegisterWaitForSingleObject does not create new thread for each request. Even if so, these threads do not create any special overhead, as per definition are only sleeping (ie. aren't scheduled for execution). B.

Roland wrote:
This would increase the number of threads seriously, since you can only wait for a very limited number of objects in a call to WaitFor.
See also http://www.microsoft.com/msj/0499/pooling/pooling.aspx B.

On Wed, 28 Jul 2004 11:06:39 +0200 Bronek Kozicki <brok@rubikon.pl> wrote:
Roland wrote:
This would increase the number of threads seriously, since you can only wait for a very limited number of objects in a call to WaitFor.
See also http://www.microsoft.com/msj/0499/pooling/pooling.aspx
I was not aware of this function until now. Thank you for pointing me towards it. But as I can see (after a quick look) the callback will not be scheduled to run in the context of the exiting thread. But this is a requirement to be able to free TLS. This is different to THREAD_DETACH which still is scheduled into the exiting thread. This might also be the reason why one should call TlsFree from there. Roland

Roland wrote:
On Wed, 28 Jul 2004 11:06:39 +0200 Bronek Kozicki <brok@rubikon.pl> wrote:
Roland wrote:
This would increase the number of threads seriously, since you can only wait for a very limited number of objects in a call to WaitFor.
See also http://www.microsoft.com/msj/0499/pooling/pooling.aspx
I was not aware of this function until now. Thank you for pointing me towards it.
I wasn't either. It looks very interesting, but what Roland points out below is a definite problem.
But as I can see (after a quick look) the callback will not be scheduled to run in the context of the exiting thread. But this is a requirement to be able to free TLS. This is different to THREAD_DETACH which still is scheduled into the exiting thread. This might also be the reason why one should call TlsFree from there.
Mike

"Michael Glassford" <glassfordm@hotmail.com> wrote in message news:ce8eev$glv$1@sea.gmane.org...
Roland wrote:
On Wed, 28 Jul 2004 11:06:39 +0200 Bronek Kozicki <brok@rubikon.pl> wrote:
[snip]
I wasn't either. It looks very interesting, but what Roland points out below is a definite problem.
But as I can see (after a quick look) the callback will not be scheduled to run in the context of the exiting thread. But this is a requirement to be able to free TLS. This is different to THREAD_DETACH which still is scheduled into the exiting thread. This might also be the reason why one should call TlsFree from there.
Either I missed something (jumped into the discussion at about this point) or just don't understand, but why should TlsFree have to be called in the context of an exiting thread? // Johan

On Thu, 29 Jul 2004 09:25:57 +0200 Johan Nilsson <johan.nilsson@esrange.ssc.se> wrote:
Either I missed something (jumped into the discussion at about this point) or just don't understand, but why should TlsFree have to be called in the context of an exiting thread?
It is my fault. I was imprecise about TlsFree. Of course there is no need to free the entire slot within the context of the exiting thread. But nevertheless you will need thread context to free the thread specific variable that is stored in your slot. Beeing on a different thread renders you unable to access the data of the exiting thread (that is what TSS stands for), and consequently you cannot free it. Normally you store a null pointer in the slot after having it freed. This is what I mistakenly called "TlsFree" which definitely is the wrong function in that case. Thank you for pointing this out. Roland

Roland wrote:
This would increase the number of threads seriously, since you can only wait for a very limited number of objects in a call to WaitFor.
Agh ... it took me some time to see your point. Yes, RegisterWaitFor.. internally uses WaitForMultipleObjects (actally it's little more complicated), which is limited to 64 handles on my version of Windows. B.

Bronek Kozicki wrote:
Roland wrote:
This would increase the number of threads seriously, since you can only wait for a very limited number of objects in a call to WaitFor.
Agh ... it took me some time to see your point. Yes, RegisterWaitFor.. internally uses WaitForMultipleObjects (actally it's little more complicated), which is limited to 64 handles on my version of Windows.
however, "new wait threads are created automatically when required." (http://msdn.microsoft.com/library/en-us/dllproc/base/registerwaitforsin gleobject.asp ) . Thus number of calls to RegisterForWait... function is not limited by capacity of WaitForMultipleObjects. B.

On Wed, 28 Jul 2004 13:38:10 +0200 Bronek Kozicki <brok@rubikon.pl> wrote:
Bronek Kozicki wrote:
Roland wrote:
This would increase the number of threads seriously, since you can only wait for a very limited number of objects in a call to WaitFor.
Agh ... it took me some time to see your point. Yes, RegisterWaitFor.. internally uses WaitForMultipleObjects (actally it's little more complicated), which is limited to 64 handles on my version of Windows.
however, "new wait threads are created automatically when required." (http://msdn.microsoft.com/library/en-us/dllproc/base/registerwaitforsin gleobject.asp ) . Thus number of calls to RegisterForWait... function is not limited by capacity of WaitForMultipleObjects.
Unfortunately that still does not account for the requirement to call the TlsFree in the context of the thread. Roland

Roland wrote:
Maybe this could be replaceed with RegisterWaitForSingleObject (waiting for thread handle)?
This would increase the number of threads seriously, since you can only wait for a very limited number of objects in a call to WaitFor.
RegisterWaitForSingleObject utilizes the builtin threadpool and is only availble in the following versions of the MS OSs which might pose a problem. Client: Requires Windows XP or Windows 2000 Professional. Server: Requires Windows Server 2003 or Windows 2000 Server. Each thread can wait on 64 objects so my guess is that the threadpool will spawn another thread for every 60-63 threads since its bound to listen to some internal events as well. And an overhead of 1 threads per ~60 isn't that bad, since any design that utilizes that many concurrent threads should be questioned anyway. And the function wont be called in the exiting threads context which might make it hard to use for the purpose. /Michel

Michel André wrote:
RegisterWaitForSingleObject utilizes the builtin threadpool and is only availble in the following versions of the MS OSs which might pose a problem. Client: Requires Windows XP or Windows 2000 Professional. Server: Requires Windows Server 2003 or Windows 2000 Server.
That's one problem. The other is that function executed on thread exit will be executed in different thread (well, you noticed that already), thus will not have access to TLS of exiting thread. Actually it will be executed after TLS has been already removed by OS. Having no access to TLS means that it won't be able to release it's memory. Even if we store copies of TLS pointers somewhere where they're also available after TLS has been removed by OS, that's still bad - destructors might need warranty that it will be executed in context of exiting thread (eg. in order to use synchronization primitives locked somewhere in the thread or to use fibers started in thread). Aaron W. LaFramboise brought really good idea of using TLS function defined in program image (ie. PE file). I didn't know that it's even possible - you may have equivalent of "DllMain" inside .exe file :-> I've seen it's handling in Windows NT core, but didn't know how to make OS aware that such function exists. As Aaron found, MSVC71 is capable of preparing such PE image - I do not know about other compilers. In case of Windows Server 2003 we also have FlsCallback (which I believe has been designed specifically for this purpose, thus is very appealing). In older Windows versions three other options are coming to my mind: * using APC (unreliable and with unforeseen CPU overhead) * manipulation in Process Environment Block structure (that's just ugly hacking, unless we find some supported way). * ditributing Boost.Threads with small DLL file, whose sole purpose is to receive DLL_THREAD_DETACH notification and pass it to Threads library B.
participants (9)
-
Bronek Kozicki
-
Johan Nilsson
-
John Maddock
-
Karel Gardas
-
Michael Glassford
-
Michel André
-
Peter Dimov
-
Roland
-
Tonko Juricic