Le 13/11/11 00:00, Phillip Hellewell a écrit :
Hi,

My class contains a member var that is a little buffer used as a cache.  Instances of this class are used concurrently (referenced through a shared_ptr).

I would like to switch my buffer to a thread_specific_ptr, but there are two big problems with using thread_specific_ptr as a member var:
The lifetime of your objects and the cache seems to be different. Have you tried to isolate the buffer (cache) in a static thread_specific_ptr?
1. There is a memory leak when my object goes away, because by design only one of the pointers gets cleaned up (the one for the thread that happens to delete the object).
2. There is undefined behavior when a new object gets created that happens to be allocated at the same address as a previously freed one.  get( ) could return a pointer to a buffer that goes with an old (now freed) object.
Yes, this is a know bug (feature for Anthony), that prevents from using them as member objects.

I try not to question the wisdom of the thread_specific_ptr authors, but given these two issues, especially #2, I have to conclude that thread_specific_ptr is only suitable for statics / globals.  It is wholly unfit to be used as a member variable (except in a singleton class I guess).

The next best thing I can think of for my class is to just have a std::map<thread_id, void*>, with synchronized access of course, and I clean up all the pointers in the map in the DTOR.  That would work just great, except I really do need the pointers to also get cleaned up (and removed from my map) when the corresponding threads go away.  Some of my objects can live a very long time, whilst threads get created and destroyed off and on, so without this functionality the map could grow indefinitely.

So I'm stuck.  I can't use thread_specific_ptr because it won't clean up everything when my object goes away, and I can't use a map because it won't clean up anything when a thread goes away.  Is there an easy solution to this?
Note that your map is equivalent to a static thread_specific_ptr, that present no evident advantages.

If there were some way for me to hook up a callback directly to the thread cleanup function, I could add a callback to remove it from my map when the thread goes away.  But I'd also need the ability to remove that callback in my DTOR.  Does boost provide any way to do this?
Boost.Thread provides a non member function at_thread_exit()

#include
<boost/thread/thread.hpp>
template<typename Callable> void at_thread_exit(Callable func);
Effects:

A copy of func is placed in thread-specific storage. This copy is invoked when the current thread exits (even if the thread has been interrupted).

Postconditions:

A copy of func has been saved for invocation on thread exit.

Throws:

std::bad_alloc if memory cannot be allocated for the copy of the function, boost::thread_resource_error if any other error occurs within the thread library. Any exception thrown whilst copying func into internal storage.

Is this what you were looking for?

I can't be the first person to want a thread-specific, object-specific pointer, can I?


My advice is use the static thread_specific_ptr ;-)

Best,
Vicente