Original Post
Just a suggestion leading on from the discussion here. Use the OS's thread local functionality, mostly it's no critical sections or mutexes required. They are also fairly easy to wrap, here is my own code for it, feel free to incorporate this into angelscript. Autocleanup of the TLS data on windows does require a dll, I simply split thread local storage into it's own lib on windows for that reason. This code makes the assumption that thread local keys are created in the main thread. It comes from my sourceforge project http://ldk.sourceforge.net/ and is zlib licensed, and there's other stuff in there that may well be useful for angelscript because I designed this library to become the base of a hard realtime scripting language. [Edited by - penguinpusher on June 13, 2007 5:50:54 AM]
//ThreadLocalStorage.h
extern "C"
{
//////////////////////////////////////////////////////////////////////////////////////
/// \ingroup Threading
/// \addtogroup ThreadLocalStorage
/// @{
///
/// Programs often need global or static variables that have different values in
/// different threads. Since threads share one memory space, this cannot be achieved
/// with regular variables. Thread local storage is the answer to this need.
///
/// Each thread possesses a private memory block, the thread-local data area (TLD).
/// This area is indexed by TLS keys. The TLD area associates values of type void *
/// to TLS keys. TLS keys are common to all threads, but the value associated with
/// a given TLS key can be different in each thread.
///
/// For concreteness, the TLS areas can be viewed as arrays of void * pointers, TLS
/// keys as integer indices into these arrays, and the value of a TLS key as the value
/// of the corresponding array element in the calling thread.
///
/// When a thread is created, its TLS area initially associates NULL with all keys.
/// This behavior is undocumented on MS Windows.
///
/// This description was adapted from the \em pthread_key_create GNU-Linux manpage.
//////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////
/// \typedef void (*ThreadLocalDtor) (void*)
/// \brief A pointer to a function used to free a piece of thread local storage.
///////////////////////////////////////////////////////////////////////////////////////
typedef void (*ThreadLocalDtor) (void*);
//////////////////////////////////////////////////////////////////////////////////////
/// \typedef size_t TLSKey
/// \brief A key used to access thread local storage.
//////////////////////////////////////////////////////////////////////////////////////
typedef size_t TLSKey;
//////////////////////////////////////////////////////////////////////////////////////
/// \fn TLSKey threadLocalCreateKey(ThreadLocalDtor dtor=NULL)
/// \brief Create a key for thread local storage.
/// \param dtor A pointer to a function to free a piece of thread local storage.
/// \return A unique key to be used with \em threadLocalSet() and
/// \em threadLocalGet().
//////////////////////////////////////////////////////////////////////////////////////
LDK_TLS_API TLSKey threadLocalCreateKey(ThreadLocalDtor dtor=NULL);
//////////////////////////////////////////////////////////////////////////////////////
/// \fn void threadLocalSet(TLSKey key, void* object)
/// \brief Associate an object with a key for the current thread.
/// \param key The unique identifier associated with an object in the current thread.
/// \param object The object to associate with \em key in the current thread.
//////////////////////////////////////////////////////////////////////////////////////
LDK_TLS_API void threadLocalSet(TLSKey key, void* object);
//////////////////////////////////////////////////////////////////////////////////////
/// \fn void* threadLocalGet(TLSKey key)
/// \brief Get the object associated with \em key for the current thread.
/// \param key The unique identifier associated with an object in the current thread.
/// \return NULL if there is nothing associated with a key in the current thread,
/// otherwise the associated object.
/////////////////////////////////////////////////////////////////////////////////////
LDK_TLS_API void* threadLocalGet(TLSKey key);
/// @}
// ThreadLocalStorage.cpp
#include "LDK/ThreadLocalStorage.h"
#include <assert.h>
#ifdef unix
#include <pthread.h>
void* threadLocalGet(TLSKey key)
{
return pthread_getspecific(key);
}
TLSKey threadLocalCreateKey(ThreadLocalDtor dtor)
{
TLSKey key = 0;
int test = pthread_key_create((pthread_key_t*)&key, dtor);
assert(!test);
return key;
}
void threadLocalSet(TLSKey key, void* data)
{
int test = pthread_setspecific(key, data);
assert(!test);
}
#elif defined _WINDOWS
#include <windows.h>
#include <map>
#ifdef _MSC_VER
#pragma warning (disable : 4267)
#endif
namespace
{
typedef std::map<TLSKey,ThreadLocalDtor> TLSMap;
TLSMap gTLSCleanup;
}
void* threadLocalGet(TLSKey key)
{
return TlsGetValue(key);
}
TLSKey threadLocalCreateKey(ThreadLocalDtor dtor)
{
TLSKey key = TlsAlloc();
assert(key != TLS_OUT_OF_INDEXES);
gTLSCleanup[key] = dtor;
return key;
}
void threadLocalSet(TLSKey key, void* data)
{
int test = TlsSetValue(key, data);
assert(test);
}
void threadLocalCleanup()
{
TLSMap::iterator i = gTLSCleanup.begin();
while(i != gTLSCleanup.end())
{
void* data = threadLocalGet((*i).first);
if(data && (*i).second)
(*i).second(data);
i++;
}
}
bool __stdcall DllMain(HINSTANCE hndl, DWORD reason, LPVOID reserved)
{
switch(reason)
{
case DLL_PROCESS_ATTACH:
//do nothing
break;
case DLL_THREAD_ATTACH:
//do nothing
break;
case DLL_THREAD_DETACH:
threadLocalCleanup();
break;
case DLL_PROCESS_DETACH:
//do nothing?
break;
}
return true;
}
#ifdef _MSC_VER
#pragma warning (default : 4267)
#endif
#endif //unix