static & thread_local variables¶

static & non-local variables¶

  • initialization of static and non-local variables with dynamic initialization is thread-safe
namespace bcc1 {

const auto& get_table() {
    static const vector<type_index> result = {typeid(int), typeid(long), typeid(short)};
    return result;
}

} // namespace bcc1
  • Thread safety only applies to object initialization
    • If there is writeable access, additional thread safety measures must be used
    • Thread-safety only applies to objects individually, not collectively
  • Immediately invoked lambda expressions provide a nice way to perform complex initialization
    • Known as 'IIFE' (pronounced "iffy") for Immediately Invoked Function Expression, from JavaScript.
namespace bcc2 {

const auto& get_table() {
    static const auto result = [] {
        vector<type_index> r{typeid(int), typeid(long), typeid(short)};
        sort(begin(r), end(r));
        return r;
    }();
    return result;
}

} // namespace bcc2
  • The thread safety construct imposes a negligligable performance impact (difficult to measure) on each access

thread_local variables¶

  • thread_local implies static storage duration
  • non-local thread_local variables with dynamic initialization are initialized at the start of every thread start
    • local thread_local variables are initialized on first execution in a given thread
  • access to a thread_local imposes about a 15% performance penalty (at least on Apple platforms) compared to accessing a static variable
namespace {

auto& context() {
    thread_local vector<string> result;
    return result;
}

} // namespace bcc3
  • Access to a thread_local variable doesn't require synchronization
    • Unless it is otherwise shared to a differnt thread
namespace {

void do_stuff() { cout << "context: " << context().back() << endl; }

} // namespace
context().push_back("selecting");
do_stuff();
context().push_back("painting");
do_stuff();
context().pop_back();
do_stuff();
context().pop_back();

Recommendations¶

  • Avoid non-local variables except for constexpr variables
    • Dynamic initialization of non-local variables impacts startup
    • Non-local thread_local variables impact the startup of every thread
  • When you must use a dynamically initialized singleton make it a static local variable
    • Prefer const to ensure thread safety
    • If mutable, consider making it a sequential process
  • thread-local local variables can be a useful tool for establishing auxiliary scope information
    • Drawing contexts
    • Transactions
    • Memory allocators
    • Caches

Homework¶

  • Find and fix one of:
    • A non-local with dynamic initialization
    • A local static which does not have thead-safe initialization
    • A use of pthread_once(), boost::call_once() or similar (simplify)
    • A use of pthread_getspecific(), boost::thread_specific_ptr() or similar (simplify)
    • A local static with dynamic initialization which could be constexpr