Как выделить поток локального хранилища? - PullRequest
56 голосов
/ 16 мая 2011

В моей функции есть переменная, которая является статической, но я бы хотел, чтобы она была статической для каждого потока.

Как я могу выделить память для моего класса C ++ так, чтобы у каждого потока был свойсобственная копия экземпляра класса?

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

  instance->doSomething();
}

Это в Linux.Я не использую C ++ 0x и это gcc v3.4.6.

Ответы [ 9 ]

67 голосов
/ 16 мая 2011
#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();
64 голосов
/ 29 марта 2013

Стоит отметить, что в C ++ 11 вводится ключевое слово thread_local.

Вот пример из Спецификаторы продолжительности хранения :

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

Возможный вывод:

Rage counter for a: 2
Rage counter for main: 2
Rage counter for b: 2
14 голосов
/ 18 мая 2011

boost::thread_specific_ptr - лучший способ для переносимого решения.

В Linux и GCC вы можете использовать __thread модификатор .

Таким образом, ваша переменная экземпляра будет выглядеть так:

static __thread MyClass *instance = new MyClass();
11 голосов
/ 16 мая 2011

Если вы используете Pthreads, вы можете сделать следующее:

//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();
}
4 голосов
/ 23 ноября 2015

C ++ 11 указывает тип хранилища thread_local, просто используйте его.

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

Одной из дополнительных оптимизаций является выделение локального хранилища потока.

3 голосов
/ 16 мая 2011

В Windows вы можете использовать TlsAlloc и TlsFree для выделения хранилища в локальном хранилище потоков.

Чтобы установить и получить значения в TLS, вы можете использовать TlsSetValue и TlsGetValue соответственно

Здесь вы можете увидеть пример того, как он будет использоваться.

3 голосов
/ 16 мая 2011

Если вы работаете с MSVC ++, вы можете прочитать Thread Local Storage (TLS)

И тогда вы можете увидеть этот пример .

Кроме того, имейте в виду Правила и ограничения для TLS

2 голосов
/ 01 ноября 2014

Просто примечание ... MSVC ++ поддерживает declspec (поток) из VSC ++ 2005

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

Основная проблема заключается в том, что переменные (которые решаются в boost :: thread_specific_ptr) помечены как не могут содержать ctor или dtor.

1 голос
/ 22 июня 2016

Folly (библиотека с открытым исходным кодом Facebook) имеет переносимую реализацию локального хранилища потоков.

По словам авторов:

Улучшено локальное хранилище потоков длянетривиальные типы (скорость аналогична pthread_getspecific, но потребляет всего один pthread_key_t и в 4 раза быстрее boost::thread_specific_ptr).

Если вы ищете переносимую реализацию Local Storage Thread,эта библиотека - хороший вариант.

...