Как выделить локальное хранилище потоков?
У меня есть переменная в моей статической функции, но я бы хотел, чтобы она была статичной по каждому потоку.
Как я могу выделить память для моего класса С++, чтобы каждый поток имел свою собственную копию экземпляра класса?
AnotherClass::threadSpecificAction()
{
// How to allocate this with thread local storage?
static MyClass *instance = new MyClass();
instance->doSomething();
}
Это на Linux. Я не использую С++ 0x, и это gcc v3.4.6.
Ответы
Ответ 1
#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();
Ответ 2
Стоит отметить, что С++ 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
Ответ 3
boost::thread_specific_ptr
- лучший способ переносить решение.
В Linux и GCC вы можете использовать __thread
модификатор.
Итак, ваша переменная экземпляра будет выглядеть так:
static __thread MyClass *instance = new MyClass();
Ответ 4
Если вы используете 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();
}
Ответ 5
С++ 11 определяет тип хранения thread_local
, просто используйте его.
AnotherClass::threadSpecificAction()
{
thread_local MyClass *instance = new MyClass();
instance->doSomething();
}
Одна дополнительная оптимизация - это также выделять локальное хранилище потоков.
Ответ 6
Если вы работаете с MSVС++, вы можете прочитать Thread Local Storage (TLS)
И затем вы можете увидеть этот пример.
Также обратите внимание на Правила и ограничения для TLS
Ответ 7
В Windows вы можете использовать TlsAlloc и TlsFree для распределите хранилище в локальном хранилище потоков.
Чтобы установить и получить значения с помощью TLS, вы можете использовать TlsSetValue и TlsGetValue, соответственно
Здесь вы можете увидеть пример того, как он будет использоваться.
Ответ 8
Просто примечание...
MSVС++ поддерживает declspec (thread) из VSС++ 2005
#if (_MSC_VER >= 1400)
#ifndef thread_local
#define thread_local __declspec(thread)
#endif
#endif
Основная проблема (которая решается в boost:: thread_specific_ptr) переменные, помеченные им, не могут содержать ctor или dtor.
Ответ 9
Folly (Facebook Open-Source Library) имеет переносимую реализацию локального хранилища потоков.
По словам авторов:
Улучшено локальное хранилище потоков для нетривиальных типов (аналогичная скорость, как pthread_getspecific
, но потребляет только один pthread_key_t
и в 4 раза быстрее чем boost::thread_specific_ptr
).
Если вы ищете переносимую реализацию Local Storage Thread, эта библиотека является хорошим вариантом.