Using /clr and __declspec(thread)

Sorry I haven't been writing much lately, but a lot has been going on in Expression land.  I've switched over to working on build and setup development so you can expect to see the flavor of my posts change somewhat.

Here's a frustrating bit I ran into playing around with C++/CLI:  __declspec(thread) isn't supported by the CLR.  You may get the application to compile properly, but you'll get the following error when trying to run:

"The application failed to initialize properly (0xc000007b)."

You can still use thread locals, but you're stuck managing the TLS_ apis yourself.  I'm including a simple template as one suggestion on how to do this:

template <typename T>

class ThreadLocal

{

private:

DWORD threadLocalIndex;

 

       ThreadLocal(ThreadLocal const&);

 

       T *GetPointer(void)

       {

              return static_cast<T*>(::TlsGetValue(this->threadLocalIndex));

       }

 

       void SetPointer(T *value)

       {

              ::TlsSetValue(this->threadLocalIndex, static_cast<void*>(value));

       }

 

public:

       void SetValue(const T &value)

       {

              T* currentPointer = this->GetPointer();

              if (currentPointer == NULL)

              {

                     this->SetPointer(new T(value));

              }

              else

              {

                     *currentPointer = value;

              }

       }

 

       T &GetValue(void)

       {

              T* currentPointer = this->GetPointer();

              if (currentPointer == NULL)

              {

                     this->SetPointer(new T());

              }

              return *this->GetPointer();

       }

 

       void DeleteValue()

       {

              T* currentPointer = this->GetPointer();

              if (currentPointer != NULL)

              {

                     delete currentPointer;

                     this->SetPointer(NULL);

              }

       }

 

       ThreadLocal(const T& value)

       {

              this->threadLocalIndex = ::TlsAlloc();

              this->SetValue(value);

       }

 

       ThreadLocal()

       {

this->threadLocalIndex = ::TlsAlloc();

       }

 

       virtual ~ThreadLocal()

       {

              this->DeleteValue();

              ::TlsFree(this->threadLocalIndex);

       }

};

 

The above template can replace a __declspec(thread) variable fairly easily.  It will handle allocating and deallocating for you.  Simple example:

static __declspec(thread) int threadMeaning=42;

... becomes ..

static ThreadLocal<int> threadMeaning(42);

Using the ThreadLocal is done through SetValue() and GetValue()  ie- threadMeaning.SetValue(2001).

The example doesn't have error checking and I haven't done anything terribly fancy. You really should try and use the framework for your thread locals if you can.  If you can't, hopefully this will be of use.

Comments