Obecnie w VC++ (a także w gcc z tego co wiem) można zrobić takie TLSy:
class A
{
...
__declspec(thread) static int localVar;
}
int A::localVar = 0;
Zmienna localVar musi być statyczna, inaczej kompilator tego nie skompiluje. A ja właśnie chciał bym, żeby ta zmienna nie była statyczna, tak żeby localVar była jednocześnie powiązana z instancją klasy oraz z wątkiem. Przykładowo w Javie da się coś takiego bez żadnego problemu zrobić:
class Klazz
{
public ThreadLocal<Integer> uniqueNum = new ThreadLocal<Integer>() {
@Override protected Integer initialValue() {
return 0;
}
};
}
public class Main {
public static void main(String[] args) {
Klazz k1 = new Klazz();
Klazz k2 = new Klazz();
k1.uniqueNum.set(1);
System.out.println("Val: " + Integer.toString(k1.uniqueNum.get()));
System.out.println("Val: " + Integer.toString(k2.uniqueNum.get()));
}
}
Jedyne co mi w C++ przychodzi do głowy to samemu stworzyć taką klasę o tak:
template<typename T>
class ThreadLocal
{
public:
T& ref(void* ptr)
{
if(localMap == 0)
{
localMap = new std::map<void*, T>;
}
return (*localMap)[ptr];
}
void release()
{
delete localMap;
localMap = 0;
}
private:
__declspec(thread) static std::map<void*, T>* localMap;
};
template<typename T> std::map<void*, T>* ThreadLocal<T>::localMap = 0;
class A
{
public:
void set(){localA.ref(this) = 1;}
int get(){return localA.ref(this);}
void release(){localA.release();}
private:
ThreadLocal<int> localA;
};
A a1, a2;
a1.set();
printf("%d %d", a1.get(), a2.get());
a1.release();
a2.release();
Problemy są dwa:
- Wydajność - muszę mieć dodatkowy kontener w którym będę wyszukiwał this.
- Zwalnianie pamięci - na koniec każdego wątku muszę wywoływać metodę release, która mi zwolni pamięc.
Pierwszy punkt da się przełknąć, natomiast 2 jest wybitnie irytujący. Na Windowsie o ile mi wiadomo nie ma sposobu na ustawienie callbacka, który powiadomi mnie o tym, że dany thread wychodzi (pomijam wszystkie brudne triki typu hookowanie IAT, notyfikacja z jądra itd). Używając highlevelowego freameworku jak pthreads mogę użyć np. pthreads_cleanup_push do zarejestrowania takiego callbacku, ale ja niekoniecznie chcę używać pthreads.
Może ktoś zna lepsze rozwiązania tego problemu bo nie chce mi się wierzyć, że nic lepszego nie istnieje...