J'ai une variable dans ma fonction qui est statique, mais j'aimerais qu'elle soit statique par thread.
Comment puis-je allouer la mémoire pour ma classe C++ de sorte que chaque thread ait sa propre copie de l'instance de classe?
AnotherClass::threadSpecificAction()
{
// How to allocate this with thread local storage?
static MyClass *instance = new MyClass();
instance->doSomething();
}
C'est sous Linux. Je n'utilise pas C++ 0x et c'est gcc v3.4.6.
#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();
Il est à noter que C++ 11 introduit le thread_local
mot-clé.
Voici un exemple de spécificateurs de durée de stockage :
#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;
}
Sortie possible:
Rage counter for a: 2
Rage counter for main: 2
Rage counter for b: 2
boost::thread_specific_ptr
est le meilleur moyen en tant que solution portable.
Sous Linux et GCC, vous pouvez utiliser __thread
modificateur .
Votre variable d'instance ressemblera donc à:
static __thread MyClass *instance = new MyClass();
Si vous utilisez Pthreads, vous pouvez effectuer les opérations suivantes:
//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 spécifie un thread_local
type de stockage, utilisez-le.
AnotherClass::threadSpecificAction()
{
thread_local MyClass *instance = new MyClass();
instance->doSomething();
}
Une optimisation facultative consiste également à allouer sur le stockage local des threads.
Si vous travaillez avec MSVC++, vous pouvez lire Thread Local Storage (TLS)
Et puis vous pouvez voir ceci exemple .
Faites également attention aux Règles et limitations pour TLS
Sous Windows, vous pouvez utiliser TlsAlloc et TlsFree pour allouer du stockage dans le stockage local des threads.
Pour définir et récupérer des valeurs avec TLS, vous pouvez utiliser TlsSetValue et TlsGetValue , respectivement
Ici vous pouvez voir un exemple sur la façon dont il serait utilisé.
Juste une note latérale ... MSVC++ prend en charge déclspec (thread) de VSC++ 2005
#if (_MSC_VER >= 1400)
#ifndef thread_local
#define thread_local __declspec(thread)
#endif
#endif
Le problème principal est (qui est résolu dans boost :: thread_specific_ptr) les variables marquées avec lui ne peuvent pas contenir ctor ou dtor.
Folly (Facebook Open-source Library) a une implémentation portable de Thread Local Storage.
Selon ses auteurs:
Amélioration du stockage local des threads pour les types non triviaux (vitesse similaire à
pthread_getspecific
mais ne consomme qu'une seulepthread_key_t
et 4x plus rapide queboost::thread_specific_ptr
).
Si vous recherchez une implémentation portable de thread de stockage local, cette bibliothèque est une bonne option.