我使用一个简单的模板类来提供线程本地存储。这只是包装std::map
和一个关键部分。然后,这不会受到任何平台特定的线程本地问题,唯一的平台要求是以整数形式获取当前线程ID。它可能比本地线程本地存储慢一点,但它可以存储任何数据类型。
下面是我的代码的减少版本。我已经删除了默认值逻辑来简化代码。由于它可以存储任何数据类型,因此只有在T
支持它们时才能使用增量和减量运算符。关键部分仅用于保护查找并插入到地图中。一旦返回引用,使用不受保护的是安全的,因为只有当前线程将使用此值。
template <class T>
class ThreadLocal
{
public:
operator T()
{
return value();
}
T & operator++()
{
return ++value();
}
T operator++(int)
{
return value()++;
}
T & operator--()
{
return --value();
}
T operator--(int)
{
return value()--;
}
T & operator=(const T& v)
{
return (value() = v);
}
private:
T & value()
{
LockGuard<CriticalSection> lock(m_cs);
return m_threadMap[Thread::getThreadID()];
}
CriticalSection m_cs;
std::map<int, T> m_threadMap;
};
要使用这个类,我一般声明静态成员的类如中
class DBConnection {
DBConnection() {
++m_connectionCount;
}
~DBConnection() {
--m_connectionCount;
}
// ...
static ThreadLocal<unsigned int> m_connectionCount;
};
ThreadLocal<unsigned int> DBConnection::m_connectionCount
它可能不是完美的每一种情况,但它涵盖了我的需要,我可以轻松地添加它是任何功能当我发现它们时错过了。
bdonlan是否正确本示例在线程退出后不会清理。但是,这很容易添加手动清理。
template <class T>
class ThreadLocal
{
public:
static void cleanup(ThreadLocal<T> & tl)
{
LockGuard<CriticalSection> lock(m_cs);
tl.m_threadMap.erase(Thread::getThreadID());
}
class AutoCleanup {
public:
AutoCleanup(ThreadLocal<T> & tl) : m_tl(tl) {}
~AutoCleanup() {
cleanup(m_tl);
}
private:
ThreadLocal<T> m_tl
}
// ...
}
然后,知道它使得明确使用ThreadLocal
都可以使用ThreadLocal::AutoCleanup
在其主要功能来清理变量的线程。
或者在DBConnection的
~DBConnection() {
if (--m_connectionCount == 0)
ThreadLocal<int>::cleanup(m_connectionCount);
}
的cleanup()
方法是静态的,以便不与operator T()
干扰的情况下。全局函数可以用来调用这个可以推断出模板参数的函数。
线程死后不能清理... – bdonlan 2009-09-22 20:01:08
你是对的,目前清理工作必须手动完成 – iain 2009-09-23 07:45:33