简体   繁体   中英

Initialization of thread-local variables

I was recently using an object whose purpose is to allocate and deallocate memory as a singleton. Something like

class MyValue
{
  // ...

  static Allocator& GetAllocator()
  {
    static Allocator allocator;
    return allocator;
  }

  // ...
};

I realized later Allocator is not thread-safe: when multiple threads were using the same allocator concurrently, occasionally strange things were happening, causing assertions and segmentation faults.

Solution: use different allocators for different threads:

class MyValue
{
  // ...

  static Allocator& GetAllocator()
  {
    thread_local static Allocator allocator;
    return allocator;
  }

  // ...
};

Awesome! My problems are gone! Just one question: Will my allocator variable be initialized every time a thread is created, even if the majority of threads won't use this variable?

The initialization of the allocator might be heavy operation, so I would like it to be initialized only when it is actually required, not in every thread.

I read that thread_local variables are allocated by each thread. Does that mean they are also constructed ? And does this allocation (or construction) happen systematically for each thread that is created or just for threads that use it?

I faintly remember hearing in a course that most details about threads and thread-local storage are platform dependent. If this is the case, I'm particularly interested in Linux and FreeBSD.


Related (interesting reads, but I could not find the answer there):

[basic.stc.thread] states

  1. All variables declared with the thread_local keyword have thread storage duration . The storage for these entities shall last for the duration of the thread in which they are created. There is a distinct object or reference per thread, and use of the declared name refers to the entity associated with the current thread.

  2. A variable with thread storage duration shall be initialized before its first odr-use (6.2) and, if constructed, shall be destroyed on thread exit.

So, you will get storage for the object in each thread. We also have [stmt.dcl]/4 that states

Dynamic initialization of a block-scope variable with static storage duration (6.7.1) or thread storage duration (6.7.2) is performed the first time control passes through its declaration; such a variable is considered initialized upon the completion of its initialization.

So, if we reach the declaration then the object will be initialized and if it has a constructor, it will be called.

If we put that all together you will have a number of constructor and destructor calls equal to the number of threads that actually reach

thread_local static Allocator allocator;

I can give you a solution to check whether it creates a new object of type Allocator each time you call GetAllocator() . Just call this method at least 5 times and check the address of all the object return. If address of all the return object are different then yes its creates different object in each call or if not it just return the address of same object each time you call GetAllocator() .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM