С++: как использовать thread_local для объявления переменной-указателя?

Я попытался объявить переменную указателя thread_local, а затем указать на новый объект в одном потоке.

thread_local static A* s_a = nullptr;

Казалось, что память нового объекта не была освобождена при уничтожении потока. Я также пытался использовать unique_ptr, но все равно утечка памяти. Я использую VS 2015.

Вот код. Добавьте точку останова в return 0, проверьте память процесса, вы увидите, что память сильно увеличивается.

#include "stdafx.h"

#include <iostream>
#include <thread>

class A
{
public:
    A(const std::string& name) : name_(name) { std::cout << (name_ + "::A").c_str() << std::endl; }
    ~A() { std::cout << (name_ + "::~A").c_str() << std::endl; }

    const std::string& name(){ return name_; }
private:
    std::string name_;
};

thread_local static std::unique_ptr<A> s_a;
//thread_local static A* s_a = nullptr;

static void test(const std::string& name)
{
    //A a(name);
    if(!s_a)
        s_a.reset(new A(name));
        //s_a = new A(name);
}

int main()
{
    for (size_t i = 0; i < 10000; i++)
    {
        {
            std::thread t0(test, "t0");
            std::thread t1(test, "t1");
            t0.join();
            t1.join();
        }
    }
    return 0;
}

Мой вопрос: как использовать thread_local для правильного объявления переменной указателя?

Спасибо.


person ldlchina    schedule 26.09.2017    source источник
comment
Я хотел бы, чтобы это был одноэлементный экземпляр в потоке, каковы сроки его удаления? почему при использовании unique_ptr все еще происходит утечка памяти?   -  person ldlchina    schedule 26.09.2017
comment
Релевантно: stackoverflow.com/questions/17668729/. И отчет об ошибке gcc. Предположительно исправлено в 4.8.2.   -  person AMA    schedule 26.09.2017
comment
static thread_local unique_ptr должно работать. Как узнать, что есть утечка?   -  person rustyx    schedule 26.09.2017
comment
Я использую VS 2015. Просто отлаживайте и останавливайтесь на строке return 0;, посмотрите память процесса в диспетчере задач.   -  person ldlchina    schedule 26.09.2017
comment
Режим выпуска или режим отладки?   -  person Mike    schedule 26.09.2017
comment
И режим выпуска, и режим отладки.   -  person ldlchina    schedule 26.09.2017
comment
Пожалуйста, покажите нам вывод этого кода!   -  person David Schwartz    schedule 26.09.2017
comment
@DavidSchwartz,Разве вы не видели проблемы с памятью? Не могли бы вы просто скопировать и вставить код и попробовать? Я не мог видеть проблему с вывода, но память действительно увеличилась много и не освободилась.   -  person ldlchina    schedule 27.09.2017
comment
@ldlchina Как вы определили, что память не была освобождена диспетчеру памяти процесса? Проверка диспетчера задач бесполезна, поскольку она будет включать в себя память, которая была освобождена локальному диспетчеру памяти, поскольку она все еще принадлежит процессу. Я думаю, что у вас вообще нет утечки, и я уверен, что ваш вывод продемонстрирует, что деструктор действительно был вызван.   -  person David Schwartz    schedule 27.09.2017
comment
@DavidSchwartz,Спасибо, вы правы. Память в диспетчере задач не соответствует действительности. Я использовал vld для демонстрации, утечек памяти не обнаружено.   -  person ldlchina    schedule 27.09.2017
comment
Из вывода можно было сказать, что был вызван деструктор. Деструктор указанного объекта может произойти только в том случае, если указатель уничтожен, а уничтожение указателя освобождает то, на что он указывает.   -  person David Schwartz    schedule 27.09.2017
comment
Правильно, вывод правильный. Просто память в диспетчере задач странная.   -  person ldlchina    schedule 29.09.2017


Ответы (2)


Стандартная поддержка многопоточности является чрезвычайно простой.

Кроссплатформенная поддержка Boost, конечно, лучше:

// for thread_specific_ptr
#include <boost/thread/tss.hpp>


// define a deleter for As
void destroy_a(A* ptr) noexcept
{
    delete ptr;
}

// define the thread_specific pointer with a deleter
boost::thread_specific_ptr<A> s_a { &destroy_a };


static void test(const std::string& name)
{
    // create the object in a manner compatible with the deleter
    if(!s_a.get())
    {
        s_a.reset(new A(name));
    }
}
person Richard Hodges    schedule 26.09.2017
comment
Спасибо, это может сработать, я не пробовал. Но по какой-то причине я не могу использовать boost. :( - person ldlchina; 26.09.2017
comment
Так много людей, похоже, не могут использовать boost в своей работе. Для меня это похоже на ходьбу на одной ноге. Обидно. - person Richard Hodges; 26.09.2017
comment
Правильно. Я согласен, что boost очень полезен. - person ldlchina; 27.09.2017

thread_local static std::unique_ptr<A> s_a; работает. Память в диспетчере задач не соответствует действительности. Я использовал vld для демонстрации памяти, утечек памяти не обнаружено.

person ldlchina    schedule 27.09.2017