
Stefan Seefeld wrote:
That's often impossible: objects and threads are orthogonal by nature: you don't always control what thread executes your code. But as it is your code that needs TLS you may have to inject TLS variables in *any* thread that comes your way, and so it has > to be cleaned up in a uniform way.
Let me try to understand it better. We start with the fact that some parts of your code can be executed by both boost and non-boost threads. A stumbling block in my case is understanding how can your code be executed by a non-boost thread unless, at some level, you explicitly make it possible. So, if I didn't completely miss the point, TLS cleanup for non-boost threads is there to spare the programmer from having to analyze complex scenarious and calling sequences which may lead to a non-boost thread visiting the 'unsuspecting' method on your object. Tony __________________________________________________ Do You Yahoo!? Tired of spam? Yahoo! Mail has the best spam protection around http://mail.yahoo.com

Tonko Juricic wrote:
Stefan Seefeld wrote:
That's often impossible: objects and threads are orthogonal by nature: you don't always control what thread executes your code. But as it is your code that needs TLS you may have to inject TLS variables in *any* thread that comes your way, and so it has >
to be cleaned up in a uniform way.
Let me try to understand it better. We start with the fact that some parts of your code can be executed by both boost and non-boost threads.
A stumbling block in my case is understanding how can your code be executed by a non-boost thread unless, at some level, you explicitly make it possible.
So, if I didn't completely miss the point, TLS cleanup for non-boost threads is there to spare the programmer from having to analyze complex scenarious and calling sequences which may lead to a non-boost thread visiting the 'unsuspecting' method on your object.
Not necessarily complex scenarios. To take an instance: the main thread is one that will never be created by Boost.Threads. If your object that uses TLS is ever called from the main thread, that would be a problem. Mike

Tonko Juricic wrote:
A stumbling block in my case is understanding how can your code be executed by a non-boost thread unless, at some level, you explicitly make it possible.
yes. A typical example is where you are writing application code (with boost::thread) that hooks up with a multi-threaded middleware (CORBA, say), i.e. your code provides callbacks that this third-party backend calls into.
So, if I didn't completely miss the point, TLS cleanup for non-boost threads is there to spare the programmer from having to analyze complex scenarious and calling sequences which may lead to a non-boost thread visiting the 'unsuspecting' method on your object.
Think about a logging library you are writing. For each log message you want to write out an id associated with the current thread. To do that you define a (global) thread_id variable, and you want that to have a different value for each executing thread. Thus, you provide a function 'get_thread_id()' that will allocate the variable on the thread-local heap the first time it is called (per thread, of course). But how is it cleaned up ? You get the idea... Stefan

"Stefan Seefeld" wrote
.... But how is it cleaned up ? You get the idea...
Sure. Example like: <code> class TLSTest { public: TLSTest() { std::cout << "Constructor" << std::endl; } ~TLSTest() { std::cout << "Destructor" << std::endl; } }; boost::thread_specific_ptr<TLSTest> ptr; int main(int argc, char* argv[]) { ptr.reset(new TLSTest()); return 0; } </code> works like a dream, taking care of programmer's sloppiness. What worried me is the case where boost program calls into non-boost (foreign) shared library. It is not rare (especially under Win32) that library call requires a callback function. Foreign shared library may have a worker thread(s) that invoke callbacks and programmer may write callback code unaware that it will be executed on some 'external' thread. Here is one very simplistic example of such 'foreign' DLL code, that I used for yesterday's testing: <code> HANDLE g_thread=NULL; DWORD g_threadid=0; DWORD WINAPI ThreadProc(LPVOID args); typedef void (*callback)(int); struct ThreadData { int iparam; callback cb; }; ThreadData g_td; BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { return TRUE; } extern "C" __declspec(dllexport) void __stdcall DLLDoSomething( int iparam, callback cb ) { g_td.iparam=iparam; g_td.cb=cb; g_thread = reinterpret_cast<HANDLE>(_beginthreadex( 0, 0, reinterpret_cast<unsigned int (__stdcall*)(void*)>(&ThreadProc), &g_td, 0, reinterpret_cast<unsigned int*>(&g_threadid))); } DWORD WINAPI ThreadProc(LPVOID args) { DWORD ret=0; ThreadData* data=reinterpret_cast<ThreadData*>(args); data->cb( data->iparam+100 ); return ret; } </code> This worked just fine, all forgotten TLS objects were cleaned properly but: <code> case DLL_THREAD_DETACH: { on_thread_exit(); break; } </code> in boost threads DLL was crucial in accomplishing that. This prompts me to try test more complex cases where shared library loading/unloading sequence may (in theory) introduce leaks. Finally, stretching one possible use case a bit too far, careless programmer may pack thread code (along with other boost code required by his app) into his own DLL and forget to provide proper cleanup calls in DLL process and thread notifications. Tony
participants (4)
-
Michael Glassford
-
Stefan Seefeld
-
Tonko Juricic
-
Tony Juricic