0

I tried to declare thread_local pointer variable and then point to a new object in one thread.

thread_local static A* s_a = nullptr;

Seemed the memory of the new object was not released when the thread destroyed. I also tried to use unique_ptr, but still memory leak. I am using VS 2015.

Here is the code. Add a break point at return 0, check the memory of the process, you will see the memory increases a lot.

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

My question is how to use thread_local to declare a pointer variable in correct way?

Thanks.

Daniel Heilper
  • 1,182
  • 2
  • 17
  • 34
ldlchina
  • 927
  • 2
  • 12
  • 31
  • I would like it is a singleton instance in a thread, what is the timing to delete it? why using unique_ptr still memory leak? – ldlchina Sep 26 '17 at 15:04
  • 1
    Relevant: https://stackoverflow.com/questions/17668729/memory-leak-in-gcc-4-8-1-when-using-thread-local. And a [gcc bug report](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=57914). Supposedly fixed in 4.8.2. – AMA Sep 26 '17 at 15:16
  • 1
    `static thread_local unique_ptr` should work. How do you know there is a leak? – rustyx Sep 26 '17 at 15:19
  • I'm using VS 2015. Simply debug and stop at line "return 0;", see the memory of the process in task manger. – ldlchina Sep 26 '17 at 15:30
  • Release mode or debug mode? – Mike Sep 26 '17 at 15:37
  • Both release mode and debug mode. – ldlchina Sep 26 '17 at 15:39
  • Please show us the output from that code! – David Schwartz Sep 26 '17 at 18:26
  • @DavidSchwartz,Did not you see the memory problem? Could you just copy and paste the code and have a try? I could not see the problem from the output, but the memory did increase a lot and not released. – ldlchina Sep 27 '17 at 01:17
  • 2
    @ldlchina How did you determine that the memory wasn't released to the process' memory manager? Checking the task manager doesn't do any good because that will include memory that has been released to the local memory manager since it still belongs to the process. I think you have no leak at all and I bet your output will demonstrate that the destructor was in fact called. – David Schwartz Sep 27 '17 at 04:20
  • @DavidSchwartz,Thanks, you are right. The memory in task manager is not true. I used vld to demonstrate, No memory leaks detected. – ldlchina Sep 27 '17 at 13:40
  • You could tell from the output that the destructor was called. The destructor of the pointed to object can only happen if the pointer is destroyed, and the destruction of the pointer frees the thing it points to. – David Schwartz Sep 27 '17 at 18:58
  • Right, the output is correct. Just the memory in the task manager is strange. – ldlchina Sep 29 '17 at 01:06

2 Answers2

1

The standard's support for threading is extremely basic.

Boost's cross-platform support is of course superior:

// 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));
    }
}
Richard Hodges
  • 68,278
  • 7
  • 90
  • 142
1

The thread_local static std::unique_ptr<A> s_a; works. The memory in task manager is not true. I used vld to demonstrate the memory, No memory leaks detected.

ldlchina
  • 927
  • 2
  • 12
  • 31