Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++11: Nontrivial Thread Local Static Variable?

I have a class X:

class X { ... }

I want to do this:

void f()
{
    thread_local static X x = ...;

    ...
}

(actually I'm using gcc so keyword is "__thread")

but I can't because you can only have trivial thread_locals.

What is the best work-around for this?

If I do it this way:

void f()
{
    thread_local static X* p = 0;

    if (!p)
       p = new X(...);

    X& x = *p;

    ...
}

then:

  1. the destructor won't be called when thread exits
  2. unnecessary dynamic memory allocation.

Update:

Here is what I have so far:

#include <iostream>
#include <type_traits>

using namespace std;

class X { public: X() { cout << "X::X()" << endl; }; ~X() { cout << "X::~X()" << endl; } };

void f()
{
        static __thread bool x_allocated = false;
        static __thread aligned_storage<sizeof(X),
             alignment_of<X>::value>::type x_storage;

        if (!x_allocated)
        {
                new (&x_storage) X;
                x_allocated = true;
                // add thread cleanup that calls destructor
        }

        X& x = *((X*) &x_storage);
}

int main()
{
        f();
}

This fixes the dynamic memory allocation problem. I just need to add the thread cleanup handler. Is there a mechanism to do this with pthreads?

like image 521
Andrew Tomazos Avatar asked Aug 21 '12 05:08

Andrew Tomazos


People also ask

Are local static variables thread safe?

So yes, you're safe.

Are static variables per thread?

static members and function local variables are not specific to each instance of a class! They are either completely global (one instance per entire executable), or are per-thread if you use C++11 and declare them thread_local . You absolutely need a member variable.

What is thread local variable in C?

Thread-local storage ( TLS ) is a mechanism by which variables are allocated such that there is one instance of the variable per extant thread. The runtime model GCC uses to implement this originates in the IA-64 processor-specific ABI, but has since been migrated to other processors as well.

How do thread local variables work?

The local variables of a function are unique to each thread that runs the function. However, the static and global variables are shared by all threads in the process. With thread local storage (TLS), you can provide unique data for each thread that the process can access using a global index.


2 Answers

The Standard describes thread_local as a storage specifier like the others (static, extern etc.) in §7.1.1. There is no restriction to "simple" data types by any definition of that word.

The problem is briefly discussed in a pre-C++11 discussion document N2147 (see the section "Thread Variable Dynamic Initialization"). That includes a description of the key problems involved in the proper implementation. Apparently the GCC implementation (static __thread) hasn't solved these problems yet (which is consistent with the fact that GCC does not officially support C++11 thread_local).

One alternative is boost::thread_specfic_ptr<> mentioned in this earlier post and described here.

Another alternative is to use a std::thread object to implement the thread and ensure each instance maintains its own copy of the variable, possibly wrapped in a unique_ptr.

like image 166
jogojapan Avatar answered Oct 09 '22 23:10

jogojapan


thread_local and __thread are, in fact, not the same thing. The main difference between them is precisely the one you stumbled upon - thread_local allows the variable to be non-POD. Unfortunately, this also has performance implications. See this question for more details about those performance implications.

like image 21
Shachar Shemesh Avatar answered Oct 09 '22 23:10

Shachar Shemesh