nlib
misc/threading/tls/tls.cpp

Sample of Thread Local Storage (TLS).

Using the nn::nlib::threading::Tls<T> class template allows a different instance of class T per thread from the same Tls<T> object.
The class T destructor is called automatically when the thread ends, allowing for resources to be released.

The MyThreadLocalClass constructor records the current time in a data member, calculates the difference between that time and the current time at the destructor, and displays this difference to the console.

using nlib_ns::threading::Tls;
using nlib_ns::threading::Thread;
class MyThreadLocalClass {
public:
MyThreadLocalClass() {
DateTime::GetNow(&datetime_);
}
~MyThreadLocalClass() {
// called just before a thread terminates
TimeSpan span;
DateTime dt;
DateTime::GetNow(&dt);
span = dt - datetime_;
nlib_printf("Thread #%d, lifetime=%d msec\n",
static_cast<int>(span.ToMilliSeconds()));
}
void DoJob(const nlib_ns::TimeSpan& span) {
}
private:
DateTime datetime_;
};
Tls<MyThreadLocalClass> g_ThreadLocal;
void ThreadFunc(int msec) {
// construct MyThreadLocalClass for this thread
g_ThreadLocal.Reset(new(std::nothrow) MyThreadLocalClass());
g_ThreadLocal->DoJob(TimeSpan(0, 0, msec, 0));
}
bool TlsDemo() {
Thread th1, th2, th3;
nlib_printf("MyThreadLocalClass's destructor shows messages.\n");
nlib_printf("Each thread owns MyThreadLocalClass via a Tls<MyThreadLocalClass> object\n\n");
// allocate a tls slot for g_ThreadLocal
errno_t e = g_ThreadLocal.Init();
if (nlib_is_error(e)) {
if (e == ENOTSUP) {
// CTR does not support destructor function
nlib_printf("It seems that nlib_tls_alloc does not support destructor function.\n");
} else {
// tls slot might be full....
}
return false;
}
th1.Start(ThreadFunc, 50);
th2.Start(ThreadFunc, 100);
th3.Start(ThreadFunc, 150);
th3.Join();
th2.Join();
th1.Join();
return true;
}
static bool SampleMain(int, char**) { return TlsDemo(); }
NLIB_MAINFUNC