Можно ли реализовать boost::thread_specific_ptr через thread_local?

Эта проблема может выглядеть странно. Я хочу сделать это, потому что у нас есть некоторый код, который нужно собрать на нескольких платформах, но некоторые платформы не поддерживают thread_local, тогда вместо этого используйте boost::thread_specific_ptr. однако создавать двоичный файл boost для каждой платформы (x86/x64/arm, debug/release, os, слишком много) неприятно.

Интересно, можно ли внедрить thread_specific_ptr через thread_local, чтобы мы могли сделать клиентский код более элегантным (избегайте #ifdef)

Я хочу иметь заголовочный файл, например:

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

Я не могу найти способ, может быть, вы можете, спасибо.


person P.X    schedule 30.03.2016    source источник
comment
В любом случае вы не избежите if-defs, ИМХО лучший способ - это взять, т.е. 'boost::thread_specific_ptr 'boost::thread_specific_ptr предоставляет переносимый механизм для локального хранилища потока, который работает на всех компиляторах, поддерживаемых Boost.Thread', или если вы не хотите строить, тогда просто скопируйте код повышения (это больно!)   -  person Vasiliy Soshnikov    schedule 30.03.2016


Ответы (1)


Можно реализовать thread_specific_ptr с помощью thread_local. Важно помнить, что thread_local — это спецификатор хранилища, а thread_specific_ptr — объект. Таким образом, технически возможно динамически создавать и уничтожать thread_specific_ptr объекты, в то время как вы не можете сделать это с thread_local объектами. Например, вы не можете поместить объект thread_local в качестве члена вашего класса.

Однако thread_local может использоваться внутри thread_specific_ptr для выбора внутренней структуры на основе текущего потока. Эта структура может содержать данные для всех thread_specific_ptr в программе и позволяет динамически создавать и удалять ее элементы. Например, для этой цели можно использовать std::map.

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;
    }
};

Это, конечно, добавляет некоторые накладные расходы по сравнению с необработанным использованием thread_local, и на самом деле это может быть немного медленнее, чем boost::thread_specific_ptr на некоторых платформах, потому что boost::thread_specific_ptr использует интерфейсы более низкого уровня, чем thread_local. Вам также придется решить проблемы, с которыми сталкивается boost::thread_specific_ptr, например, какой ключ использовать для поиска значения на карте. Но этот подход может быть полезен, если ваша цель — удалить зависимость.

person Andrey Semashev    schedule 30.03.2016