尝试编写自定义Allocate_Shared分配器并将其变为thread_local时崩溃

Crash when try to write a custom allocate_shared allocator and make it thread_local

本文关键字:thread 崩溃 local 分配器 自定义 Allocate Shared      更新时间:2023-10-16

我的程序使用make_shared在每个线程中非常频繁地创建和破坏几种类型的小对象,并且共享_ptr不会传递给另一个线程,在这种情况下,我决定去用boost :: pool编写自定义Allocate_Shared分配器作为其成员,以根据类型分配固定的内存大小。

我的代码如下:

quadallocator.h:

#include <boost/pool/pool.hpp>
template<typename T>
class ObjectAllocator
{
public:
    typedef std::size_t size_type;
    typedef std::ptrdiff_t difference_type;
    typedef T* pointer;
    typedef const T* const_pointer;
    typedef T& reference;
    typedef const T& const_reference;
    typedef T value_type;
    auto static constexpr block_size=64+sizeof(value_type);
public:
    ObjectAllocator() noexcept:pool_(block_size){}
    ObjectAllocator(const ObjectAllocator &other) noexcept :pool_(block_size){}
    ~ObjectAllocator()=default;
    template<typename U>
    ObjectAllocator(const ObjectAllocator<U> &other) noexcept :pool_(block_size){}
    template<typename U>
    ObjectAllocator& operator= (const ObjectAllocator<U> &other){
        return *this;
    }
    ObjectAllocator<T>& operator = (const ObjectAllocator &other){
        return *this;
    }
    template<typename U>
    struct rebind{ typedef ObjectAllocator<U> other; };
    T *allocate(size_type n, const void *hint=nullptr){
#ifdef _DEBUG
        assert(n==1);
#endif
        return static_cast<T*>(pool_.malloc());
    }
    void deallocate(T *ptr, size_type n){
#ifdef _DEBUG
        assert(n==1);
#endif
        pool_.free(ptr);
    }
private:
    boost::pool<> ObjectAllocator<T>::pool_(block_size);
}
template<typename T, typename U>
inline bool operator == (const ObjectAllocator<T>&, const ObjectAllocator<U>&){
    return true;
}
template<typename T, typename U>
inline bool operator != (const ObjectAllocator<T>& a, const ObjectAllocator<U> &b){
    return !(a==b);
}

namespace Allocator {
template <typename T>
thread_local ObjectAllocator<T> allocator;
}

main.cpp:

class ObjectA{
public:
    int s=0;
    void func(){
        std::cout<<s<<std::endl;
    }
    ObjectA() {//std::cout<<"()"<<std::endl;}
    ~ObjectA() {//std::cout<<"~"<<std::endl;}
};
std::vector<std::shared_ptr<ObjectA>> vec;
void test(){
    static uint32_t loop_count=1000*1000;
    for(uint32_t i=0;i<loop_count;i++){
         shared_ptr<ObjectA> packet = allocate_shared<ObjectA, ObjectAllocator<ObjectA>>(Allocator::allocator<ObjectA>);
         vec.push_back(packet);
    }
    vec.clear();
}
std::vector<std::shared_ptr<ObjectA>> vec2;
void test2(){
    static uint32_t loop_count=1000*1000;
    for(uint32_t i=0;i<loop_count;i++){
        shared_ptr<ObjectA> packet = allocate_shared<ObjectA, ObjectAllocator<ObjectA>>(Allocator::allocator<ObjectA>);
        vec2.push_back(packet);
    }
    vec2.clear();
}
int main() {
    std::thread thread1(test);
    test2();
    return 0;
}

当我尝试测试它时,它会崩溃,我不知道为什么。谁能帮助使它正确?预先感谢。

调试器在shared_ptr_base.h

中说seg故障

void* _m_get_deleter(const std :: type_info&amp; __ti)const noexcept {return _m_pi?_m_pi-> _ m_get_deleter(__ ti):nullptr;}

当我尝试使boost :: poost静态时,它在单线程中正常工作,并且在多线程中崩溃调试器说shone_ptr_base.h

中的seg故障

:_M_USE_COUNT(1),_M_WEAK_COUNT(1){}


更新:我将BOOST :: pool是静态thread_local,并且现在正常工作

template<typename T>
class ObjectAllocator
{
public:
    typedef std::size_t size_type;
    typedef std::ptrdiff_t difference_type;
    typedef T* pointer;
    typedef const T* const_pointer;
    typedef T& reference;
    typedef const T& const_reference;
    typedef T value_type;
    auto static constexpr block_size=64+sizeof(value_type);
public:
    ObjectAllocator() noexcept{}
    ObjectAllocator(const ObjectAllocator &other) noexcept {}
    ~ObjectAllocator()=default;
    template<typename U>
    ObjectAllocator(const ObjectAllocator<U> &other) noexcept {}
    template<typename U>
    ObjectAllocator& operator= (const ObjectAllocator<U> &other){
        return *this;
    }
    ObjectAllocator<T>& operator = (const ObjectAllocator &other){
        return *this;
    }
    template<typename U>
    struct rebind{ typedef ObjectAllocator<U> other; };
    T *allocate(size_type n, const void *hint=nullptr){
#ifdef _DEBUG
        assert(n==1);
#endif
        return static_cast<T*>(pool_.malloc());
    }
    void deallocate(T *ptr, size_type n){
#ifdef _DEBUG
        assert(n==1);
#endif
        pool_.free(ptr);
    }
private:
    thread_local static boost::pool<> pool_;
};
template<typename T>
thread_local boost::pool<> ObjectAllocator<T>::pool_(block_size);

template<typename T, typename U>
inline bool operator == (const ObjectAllocator<T>&, const ObjectAllocator<U>&){
    return true;
}
template<typename T, typename U>
inline bool operator != (const ObjectAllocator<T>& a, const ObjectAllocator<U> &b){
    return !(a==b);
}
namespace Allocator {
template <typename T>
thread_local static ObjectAllocator<T> allocator;
}
template <typename T, typename ...Args>
inline auto custom_make_shared(Args... args){
    return std::allocate_shared<T,ObjectAllocator<T>>(Allocator::allocator<T>,std::forward<Args>(args)...);
}

每次称为boost::poolObjectAllocator的复制构造函数。

std::allocate_shared复制分配器(cppReference)时,用于分配std::shared_ptrObjectAllocator的实例在shared_ptr被销毁之前会被其池破坏。

相关的问题:C 状态分配者DE-CORPATE问题

可能与您的问题无关,但是还有其他问题:

  • 您不加入main中的thread1。这将调用 std::terminate并崩溃您的程序。
  • boost::pool<> ObjectAllocator<T>::pool_(block_size);- ObjectAllocator<T>::零件是多余的,非标准的。(AFAIK仅在MSVC中接受)