Деструктор списка, вызывающий сбой в поточном локальном синглтон-классе - PullRequest
3 голосов
/ 26 июня 2019

Я пытался создать синглтон-класс локального потока с членом типа std::list. Во время тестирования моего решения с несколькими потоками я столкнулся со странным сбоем, вызванным деструктором std::list (точнее, методом _M_clear(), вызываемым деструктором). Это происходит даже без выполнения каких-либо операций в указанном списке. Что еще более странно - этот сбой происходит случайным образом.

Есть идеи, в чем здесь проблема?

Ниже приведен минимальный пример для представления этой ошибки:

#include <list>
#include <thread>

class tls_list_test
{
private:
    std::list<int> test_list;

    tls_list_test() = default;

    ~tls_list_test() = default;

public:
    static tls_list_test& get_instance()
    {
        thread_local tls_list_test instance;
        return instance;
    }
};

int main()
{
    std::list<std::thread> threads;

    for (int i = 0; i < 3; ++i)
    {
        std::thread thread([]()
           {
               auto& instance = tls_list_test::get_instance();
           });
        threads.push_back(std::move(thread));
    }

    for (auto& thread : threads)
    {
        thread.join();
    }

    return 0;
}

Код в std::list, вызывающий ошибку по умолчанию:

  template<typename _Tp, typename _Alloc>
    void
    _List_base<_Tp, _Alloc>::
    _M_clear() _GLIBCXX_NOEXCEPT
    {
      typedef _List_node<_Tp>  _Node;
      __detail::_List_node_base* __cur = _M_impl._M_node._M_next;
      while (__cur != &_M_impl._M_node)
    {
      _Node* __tmp = static_cast<_Node*>(__cur);
      __cur = __tmp->_M_next; // <- SEGFAULT on this line
      _Tp* __val = __tmp->_M_valptr();
#if __cplusplus >= 201103L
      _Node_alloc_traits::destroy(_M_get_Node_allocator(), __val);
#else
      _Tp_alloc_type(_M_get_Node_allocator()).destroy(__val);
#endif
      _M_put_node(__tmp);
    }
    }

Переменные GDB:

Signal = SIGSEGV (Segmentation fault)
__tmp = {std::__cxx11::_List_base<int, std::allocator>::_Node * | 0xfeeefeeefeeefeee} 0xfeeefeeefeeefeee
__val = {int * | 0x2ee4448} 0x2ee4448
this = {std::__cxx11::_List_base<int, std::allocator> * const | 0x2ee5be8} 0x2ee5be8
__cur = {std::__detail::_List_node_base * | 0xfeeefeeefeeefeee} 0xfeeefeeefeeefeee

G ++ версия:

g++ (x86_64-posix-seh-rev0, Built by MinGW-W64 project) 8.1.0

1 Ответ

0 голосов
/ 26 июня 2019

Единственная возможная причина - реализация thread_local на вашем компиляторе.Локальная переменная не является (подразумеваемой) static.Попробуйте добавить static к (локальной) переменной:

static thread_local tls_list_test instance;
...