/*------------------------------------------------------------------------------ * Copyright (C) 2003-2006 Ben van Klinken and the CLucene Team * * Distributable under the terms of either the Apache License (Version 2.0) or * the GNU Lesser General Public License, as specified in the COPYING file. ------------------------------------------------------------------------------*/ #ifndef _lucene_util_ThreadLocal_H #define _lucene_util_ThreadLocal_H #if defined(_LUCENE_PRAGMA_ONCE) # pragma once #endif #include "CLucene/util/VoidMap.h" CL_NS_DEF(util) class ThreadLocalBase: LUCENE_BASE{ public: /** * A hook called when CLucene is starting or shutting down, * this can be used for setting up and tearing down static * variables */ typedef void ShutdownHook(bool startup); protected: STATIC_DEFINE_MUTEX(ThreadLocalBase_THIS_LOCK) typedef CL_NS(util)::CLMultiMap<_LUCENE_THREADID_TYPE, ThreadLocalBase*, CL_NS(util)::CLuceneThreadIdCompare, CL_NS(util)::Deletor::ConstNullVal<_LUCENE_THREADID_TYPE>, CL_NS(util)::Deletor::ConstNullVal > ThreadLocalsType; static ThreadLocalsType threadLocals; //todo: using http://en.wikipedia.org/wiki/Thread-local_storage#Pthreads_implementation //would work better... but lots of testing would be needed first... typedef CL_NS(util)::CLSetList, CL_NS(util)::Deletor::ConstNullVal > ShutdownHooksType; static ShutdownHooksType shutdownHooks; ThreadLocalBase(); public: virtual ~ThreadLocalBase(); /** * Call this function to clear the local thread data for this * ThreadLocal. Calling set(NULL) does the same thing, except * this function is virtual and can be called without knowing * the template. */ virtual void setNull() = 0; /** * If you want to clean up thread specific memory, then you should * make sure this thread is called when the thread is not going to be used * again. This will clean up threadlocal data which can contain quite a lot * of data, so if you are creating lots of new threads, then it is a good idea * to use this function, otherwise there will be many memory leaks. */ static void UnregisterCurrentThread(); /** * Call this function to shutdown CLucene */ static void shutdown(); /** * Add this function to the shutdown hook list. This function will be called * when CLucene is shutdown. */ static void registerShutdownHook(ShutdownHook* hook); }; template class ThreadLocal: public ThreadLocalBase{ typedef CL_NS(util)::CLSet<_LUCENE_THREADID_TYPE, T, CL_NS(util)::CLuceneThreadIdCompare, CL_NS(util)::Deletor::ConstNullVal<_LUCENE_THREADID_TYPE>, _deletor > LocalsType; LocalsType locals; DEFINE_MUTEX(locals_LOCK) public: ThreadLocal(); ~ThreadLocal(); T get(); void setNull(); void set(T t); }; template ThreadLocal::ThreadLocal(): locals(false,true) { //add this object to the base's list of threadlocals to be //notified in case of UnregisterThread() _LUCENE_THREADID_TYPE id = _LUCENE_CURRTHREADID; SCOPED_LOCK_MUTEX(ThreadLocalBase_THIS_LOCK) threadLocals.insert( pair(id, this) ); } template ThreadLocal::~ThreadLocal(){ //remove this object to the base's list of threadlocals _LUCENE_THREADID_TYPE id = _LUCENE_CURRTHREADID; SCOPED_LOCK_MUTEX(ThreadLocalBase_THIS_LOCK) //remove all the thread local data for this object locals.clear(); //remove this object from the ThreadLocalBase threadLocal list ThreadLocalsType::iterator itr = threadLocals.lower_bound(id); ThreadLocalsType::iterator end = threadLocals.upper_bound(id); while ( itr != end ){ if ( itr->second == this){ threadLocals.erase(itr); break; } ++itr; } } template T ThreadLocal::get(){ return locals.get(_LUCENE_CURRTHREADID); } template void ThreadLocal::setNull(){ set(NULL); } template void ThreadLocal::set(T t){ _LUCENE_THREADID_TYPE id = _LUCENE_CURRTHREADID; locals.remove(id); if ( t != NULL ) locals.insert( pair<_LUCENE_THREADID_TYPE,T>(id, t) ); } CL_NS_END #endif