Reputation: 2356
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):
Upvotes: 3
Views: 7487
Reputation: 180990
[basic.stc.thread] states
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.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;
Upvotes: 7
Reputation: 5591
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()
.
Upvotes: 1