Как выделить локальное хранилище потоков?
У меня есть переменная в моей функции, которая является статической, но я хотел бы, чтобы она была статической на основе каждого потока.
Как я могу выделить память для моего класса 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 ответов:
#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();
стоит отметить, что 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
boost::thread_specific_ptr
- это лучший способ как портативное решение.в Linux & GCC вы можете использовать
__thread
модификатор.Так что ваш экземпляр переменной будет выглядеть так:
static __thread MyClass *instance = new MyClass();
Если вы используете 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(); }
C++11 указывает a
thread_local
тип хранения, просто использовать его.AnotherClass::threadSpecificAction() { thread_local MyClass *instance = new MyClass(); instance->doSomething(); }
одна дополнительная оптимизация заключается в том, чтобы также выделять на потоке локальное хранилище.
Если вы работаете с MSVC++, вы можете прочитать локальное хранилище потока (TLS)
и тогда вы можете увидеть это пример.
кроме того, будьте в курсе правила и ограничения для TLS
в Windows вы можете использовать TlsAlloc и TlsFree чтобы выделить хранилище в локальном хранилище потоков.
чтобы установить и получить значения в TLS, вы можете использовать TlsSetValue и TlsGetValue, соответственно
здесь вы можете увидеть пример того, как он будет использоваться.
просто замечание... MSVC++ поддерживает declspec (поток) от VSC++2005
#if (_MSC_VER >= 1400) #ifndef thread_local #define thread_local __declspec(thread) #endif #endif
основная проблема (которая решается в boost:: thread_specific_ptr) переменные, помеченные им, не могут содержать ctor или dtor.
Folly (Facebook Open-source Library) имеет портативную реализацию локального хранилища потоков.
По мнению его авторов:
улучшено локальное хранилище потоков для нетривиальных типов (аналогичная скорость, как
pthread_getspecific
но потребляет только одинpthread_key_t
, и в 4 раза быстрее чемboost::thread_specific_ptr
).Если вы ищете портативную реализацию локального потока хранения, эта библиотека является хорошим вариантом.