Skip to main content

The thread local variable for coroutines

· One min read
Bob Chen

As we all know, C++11 introduced the thread_local keyword to replace the __thread provided by the compiler, or the specific key related functions provided by the pthread library.

Here is a typical example of using thread_local.

#include <thread>

static thread_local int i = 0;

int main() {
auto th = std::thread([]{
i = 1;
});
th.join();

assert(i == 0);
}

Photon begins to support TLS for coroutines since version 0.4.0. Due to some limitations, Photon cannot achieve the same syntax as thread_local, but implements it in a close way.

#include <photon/thread/std-compat.h>

static photon::thread_local_ptr<int, int> pI(0);

int main() {
if (photon::init())
abort();
DEFER(photon::fini());

auto th = photon_std::thread([]{
*pI = 1;
});
th.join();

assert(*pI == 0);
}

In this code above, thread_local_ptr is a template class that provides pointer-like operators. You need to pass the appropriate constructor type to its template parameter, which in this example, is also a int.

When users access it in different coroutines, they will always get a separate value.

Below is a more complicated example:

class Value {
public:
explicit Value(std::string s) : m_s(std::move(s)) {}
size_t size() { return m_s.size(); }
private:
std::string m_s;
};

class A {
public:
void func();
private:
static photon::thread_local_ptr<Value, std::string> m_value;
};

static photon::thread_local_ptr<Value, std::string> m_value("123");

void A::func() {
std::cout << "Value size " << m_value->size() << std::endl;
}