Search code examples
c++c++11boostthread-local-storage

Is it possible to implement boost::thread_specific_ptr via thread_local?


This problem may looks strange. I want to do that because we have some code need to be built on several platforms, but some platform doesn't support thread_local, then use boost::thread_specific_ptr instead. however, it's unpleasing to build boost binary for every platform (x86/x64/arm, debug/release, os, too many).

I wonder if it's possible to imp thread_specific_ptr via thread_local so that we can keep client code more elegant(avoid #ifdef)

I want to have a header file like:

#if HAS_THREAD_LOCAL
class thread_specific_ptr
{
    ... // use thread_local to implement
};
#else
using boost::thread_specific_ptr
#endif

I can't find the way, maybe you can, thanks.


Solution

  • It is possible to implement thread_specific_ptr using thread_local. The important part one has to remember is that thread_local is a storage specifier and thread_specific_ptr is an object. As such it's technically possible to dynamically create and destroy thread_specific_ptr objects while you cannot do that with thread_local objects. For instance, you cannot put a thread_local object as a member of your class.

    However, thread_local can be used internally by thread_specific_ptr to select an internal structure based on the current thread. That structure can contain data for all thread_specific_ptrs in the program, and allow dynamic creation and deletion of its elements. One could use a std::map for this purpose, for example.

    thread_local std::map< void*, std::shared_ptr< void > > thread_specific_ptr_data;
    
    template< typename T >
    class thread_specific_ptr
    {
    public:
        T* get() const
        {
            auto it = thread_specific_ptr_data.find(this);
            if (it != thread_specific_ptr_data.end())
                return static_cast< T* >(it->second.get());
            return nullptr;
        }
    };
    

    That, of course, adds some overhead compared to the raw use of thread_local, and it can actually be a bit slower than boost::thread_specific_ptr on some platforms because boost::thread_specific_ptr uses lower-level interfaces than thread_local. You would also have to solve the problems boost::thread_specific_ptr is facing, like what key to use to look for the value in the map. But this approach can be useful if your goal is to remove the dependency.