57

I have a variable in my function that is static, but I would like it to be static on a per thread basis.

How can I allocate the memory for my C++ class such that each thread has its own copy of the class instance?

AnotherClass::threadSpecificAction()
{
  // How to allocate this with thread local storage?
  static MyClass *instance = new MyClass();

  instance->doSomething();
}

This is on Linux. I'm not using C++0x and this is gcc v3.4.6.

WilliamKF
  • 41,123
  • 68
  • 193
  • 295

9 Answers9

70
#include <boost/thread/tss.hpp>
static boost::thread_specific_ptr< MyClass> instance;
if( ! instance.get() ) {
    // first time called by this thread
    // construct test element to be used in all subsequent calls from this thread
    instance.reset( new MyClass);
}
    instance->doSomething();
ravenspoint
  • 19,093
  • 6
  • 57
  • 103
  • 10
    This. Don't bother with OS specific stuff, `boost::thread_specific_ptr` is clean, portable, and idiomatic. – Alexandre C. May 16 '11 at 18:52
  • 15
    @entheh: By super-lazy you mean those who value well-constructed example code? =). – Claudiu May 06 '14 at 16:49
  • Just note that cleanup of *instance is only performed if the exiting thread is a boost::thread – jupp0r Jan 19 '16 at 10:33
  • 4
    The original question is about "static" thread locals, which is exactly what is built into C++ via the `thread_local` keyword, so he should use C++' native support as simply as `thread_local MyClass instance;`. The `thread_specific_ptr` code in this answer is more complicated and less standard-conforming. Although not the right choice here, `thread_specific_ptr` remains useful for _dynamically_ allocating thread local objects. – user2913094 Feb 16 '16 at 02:22
  • @user2913094 GCC 3.4 unsurprisingly doesn't have that feature. Also, GCC 4.6 nor MSVC – sehe Jun 10 '16 at 21:09
69

It is worth noting that C++11 introduces the thread_local keyword.

Here is an example from Storage duration specifiers:

#include <iostream>
#include <string>
#include <thread>
#include <mutex>

thread_local unsigned int rage = 1; 
std::mutex cout_mutex;

void increase_rage(const std::string& thread_name)
{
    ++rage;
    std::lock_guard<std::mutex> lock(cout_mutex);
    std::cout << "Rage counter for " << thread_name << ": " << rage << '\n';
}

int main()
{
    std::thread a(increase_rage, "a"), b(increase_rage, "b");
    increase_rage("main");

    a.join();
    b.join();

    return 0;
}

Possible output:

Rage counter for a: 2
Rage counter for main: 2
Rage counter for b: 2
Inverse
  • 4,408
  • 2
  • 26
  • 35
Deqing
  • 14,098
  • 15
  • 84
  • 131
  • 2
    GCC added support for `thread_local` in 4.8. If you're using 4.7 or earlier, you'll need to use `__thread` instead to specify the storage class. – Drew Noakes May 24 '13 at 17:39
  • 1
    This is exactly what I need. But why need `mutex`? Science the `thead_local` is private for each thread? –  Aug 08 '15 at 09:29
  • @reavenisadesk, you shouldn't need a `mutex` for any `thread_local` variable. – russoue Oct 08 '15 at 20:58
  • 1
    Unfortunately getting thread_local to work on OSX is a bit of a nightmare: http://stackoverflow.com/questions/28094794/why-does-apple-clang-disallow-c11-thread-local-when-official-clang-supports – Alex Jansen Nov 04 '15 at 19:44
  • 5
    @reavenisadesk, The `mutex` just syncs the output, because the stream doesn't write everything at once. Without the lock, you would read something like "Rage counter for Rage counter for aRage counter for : main"... – Youka Jan 16 '16 at 17:01
  • osx-provided clang still doesn't support `thread_local` as of may 10, 2016 :( i see no plans or horizon for support of this feature, which sucks because `thread_local` would have helped solve a performance problem for me. – ofloveandhate May 10 '16 at 19:48
  • responding to my preceding comment, XCode 8 brings `thread_local` to their clang. g2g – ofloveandhate Sep 20 '16 at 18:05
14

boost::thread_specific_ptr is the best way as it portable solution.

On Linux & GCC you may use __thread modifier.

So your instance variable will look like:

static __thread MyClass *instance = new MyClass();
Drew Noakes
  • 300,895
  • 165
  • 679
  • 742
tvn
  • 634
  • 3
  • 6
  • 2
    Beware of the destructor not being executed on MyClass when using __thread. (boost::thread_specific_ptr or thread_local MyClass do execute the destructor.) – David L. Oct 30 '13 at 10:26
11

If you're using Pthreads you can do the following:

//declare static data members
pthread_key_t AnotherClass::key_value;
pthread_once_t AnotherClass::key_init_once = PTHREAD_ONCE_INIT;

//declare static function
void AnotherClass::init_key()
{
    //while you can pass a NULL as the second argument, you 
    //should pass some valid destrutor function that can properly
    //delete a pointer for your MyClass
    pthread_key_create(&key_value, NULL);
}

void AnotherClass::threadSpecificAction()
{
  //Initialize the key value
  pthread_once(&key_init_once, init_key);

  //this is where the thread-specific pointer is obtained
  //if storage has already been allocated, it won't return NULL

  MyClass *instance = NULL;
  if ((instance = (MyClass*)pthread_getspecific(key_value)) == NULL)
  {
    instance = new MyClass;
    pthread_setspecific(key_value, (void*)instance);
  }

  instance->doSomething();
}
Jason
  • 31,834
  • 7
  • 59
  • 78
4

C++11 specifies a thread_local storage type, just use it.

AnotherClass::threadSpecificAction()
{
  thread_local MyClass *instance = new MyClass();
  instance->doSomething();
}

One optional optimization is to also allocate on thread local storage.

rustyx
  • 80,671
  • 25
  • 200
  • 267
Arne
  • 7,921
  • 9
  • 48
  • 66
  • 3
    Not implemented on OS X or iOS, though. – jupp0r Jan 19 '16 at 10:34
  • @jupp0r then your OS X compiler is not C++11-compliant. [dcl.stc/1](http://eel.is/c++draft/dcl.stc#1) : *storage-class-specifier: static, thread_local, extern, mutable*. – rustyx Aug 17 '16 at 09:06
  • @rustyx: yes, AppleClang is not C++11-compliant (as of now, support for `thread_local` is coming in XCode8). – jupp0r Aug 17 '16 at 13:27
4

If you're working with MSVC++, you can read Thread Local Storage (TLS)

And then you can see this example.

Also, be aware of the Rules and Limitations for TLS

Nawaz
  • 353,942
  • 115
  • 666
  • 851
  • 3
    Downvoted because in light of the rules and limitations I don't see how that answers the question. There's no mention of [C2482](https://msdn.microsoft.com/en-us/library/s2b5styy%28v=vs.100%29.aspx) or [C2483](https://msdn.microsoft.com/en-us/library/9zxe5aww%28v=vs.100%29.aspx). – Andreas Haferburg Jun 03 '15 at 14:31
  • Upvoting because the title of this question does not mention Linux. And search traffic is driven from the title, not some subtle disclaimers in the body of the question. However, those are useful links. – Contango Mar 16 '20 at 10:17
3

On Windows you can use TlsAlloc and TlsFree to allocate storage in the threads local storage.

To set and retrieve values in with TLS, you can use TlsSetValue and TlsGetValue, respectively

Here you can see an example on how it would be used.

Tony The Lion
  • 61,704
  • 67
  • 242
  • 415
2

Just a side note... MSVC++ supports declspec(thread) from VSC++2005

#if (_MSC_VER >= 1400)
  #ifndef thread_local     
    #define thread_local __declspec(thread)
  #endif
#endif

Main problem is(which is solved in boost::thread_specific_ptr) variables marked with it can't contain ctor or dtor.

Arek Bal
  • 712
  • 8
  • 13
1

Folly (Facebook Open-source Library) has a portable implementation of Thread Local Storage.

According its authors:

Improved thread local storage for non-trivial types (similar speed as pthread_getspecific but only consumes a single pthread_key_t, and 4x faster than boost::thread_specific_ptr).

If your looking for a portable implementation of Local Storage Thread, this library is a good option.

chema989
  • 3,962
  • 2
  • 20
  • 33