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):
Destruction of thread_local objects
What does the thread_local mean in C++11?
What is the performance penalty of C++11 thread_local variables in GCC 4.8?
[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;
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().
Related
Given the following example:
struct test
{
const char* data;
const int number;
};
struct test* foo()
{
static struct test t = {
"this is some data",
69
};
return &t;
}
is the call to foo thread safe? In other words, is the structure initialized only once in a thread-safe manner? Does it make a difference if this is compiled in C or C++?
The distinction exists in C/C++ prior to C++ 11 and in C++ 11 or later (Earlier standards lacked any provisions for threading.).
As you can see here: C++ Static local variables, since C++11 is it guaranteed by the standard that a static local variable will be initialized only once. There is a specific note regarding locks that can be applied to ensure single initializing in a multi threaded environment:
If multiple threads attempt to initialize the same static local
variable concurrently, the initialization occurs exactly once (similar
behavior can be obtained for arbitrary functions with std::call_once).
Note: usual implementations of this feature use variants of the
double-checked locking pattern, which reduces runtime overhead for
already-initialized local statics to a single non-atomic boolean
comparison.
The rules in C are specified here: C Storage duration:
static storage duration. The storage duration is the entire execution
of the program, and the value stored in the object is initialized only
once, prior to main function. All objects declared static and all
objects with either internal or external linkage that aren't declared
_Thread_local (since C11) have this storage duration.
Since C++11, object initialization will be made only by one thread, other threads will wait till it complete. See this thread for reference.
The book Object oriented programming in c++ by Robert Lafore says,
A static local variable has the visibility of an automatic local
variable (that is, inside the function containing it). However, its
lifetime is the same as that of a global variable, except that it
doesn’t come into existence until the first call to the function
containing it. Thereafter it remains in existence for the life of the
program
What does coming into existence after first call of function mean? The storage for static local is allocated at the time program is loaded in the memory.
The storage is allocated before main is entered, but (for example) if the static object has a ctor with side effects, those side effects might be delayed until just before the first time the function is called.
Note, however, that this is not necessarily the case. Constant initialization is only required to happen before that block is entered (not necessarily just as execution "crosses" that definition). Likewise, implementations are allowed to initialize other block-scope static variables earlier than required under some circumstances (if you want to get into the gory details of the circumstances, you can look at [basic.start.init] and [stmt.dcl], but it basically comes down to: as long as it doesn't affect the value with which it's initialized. For example, if you had something like:
int i;
std::cin >> i;
{
static int x = i;
...the implementation wouldn't be able to initialize x until the block was entered, because the value with which it was being initialized wouldn't be known until them. On the other hand, if you had:
{
static int i = 0;
...the implementation could carry out the initialization as early as it wished (and most would/will basically carry out such an initialization at compile time, so it won't involve executing any instructions at run-time at all). Even for less trivial cases, however, earlier initialization is allowed when logically possible (e.g., the value isn't coming from previous execution).
In C++ storage duration of an object (when raw memory gets allocated for it) and lifetime of an object are two separate concepts. The author was apparently referring to the latter one when he was talking about object's "coming into existence".
In general case it is not enough to allocate storage for an object to make it "come into existence". Lifetime of an object with non-trivial initialization begins once its initialization is complete. For example, an object of a class with a non-trivial constructor does not officially "live" until its constructor has completed execution.
Initialization of a static local object is performed when the control passes over the declaration for the very first time. Before that the object does not officially exist, even if the memory for it is already allocated.
Note that the author is not painstakingly precise in his description. It is not sufficient to just call the function containing the declaration. The control has to pass through the declaration of the object for it to begin its lifetime. If the function contains branching, this does not necessarily happen during the very first call to the function.
For object with trivial initialization (like int objects), there's no difference between storage duration and lifetime. For such objects allocating memory is all that needs to be done. But in general case allocating memory alone is not sufficient.
It means that the static variable inside a function doesn't get initialized (by the constructor or the assignment operator) until the first call for that function.
As soon as the function, which contains a static local variable, is called the static local variable is initialized.
I have C++ code which declares static-lifetime variables which are initialized by function calls. The called function constructs a vector instance and calls its push_back method. Is the code risking doom via the C++ static initialization order fiasco? If not, why not?
Supplementary information:
What's the "static initialization order fiasco"?
It's explained in C++ FAQ 10.14
Why would I think use of vector could trigger the fiasco?
It's possible that the vector constructor makes use of the value of another static-lifetime variable initialized dynamically. If so, then there is nothing to ensure that vector's variable is initialized before I use vector in my code. Initializing result (see code below) could end up calling the vector constructor before vector's dependencies are fully initialized, leading to access to uninitialized memory.
What does this code look like anyway?
struct QueryEngine {
QueryEngine(const char *query, string *result_ptr)
: query(query), result_ptr(result_ptr) { }
static void AddQuery(const char *query, string *result_ptr) {
if (pending == NULL)
pending = new vector<QueryEngine>;
pending->push_back(QueryEngine(query, result_ptr));
}
const char *query;
string *result_ptr;
static vector<QueryEngine> *pending;
};
vector<QueryEngine> *QueryEngine::pending = NULL;
void Register(const char *query, string *result_ptr) {
QueryEngine::AddQuery(query, result_ptr);
}
string result = Register("query", &result);
Fortunately, static objects are zero-initialised even before any other initialisation is performed (even before the "true" initialisation of the same objects), so you know that the NULL will be set on that pointer long before Register is first invoked.1
Now, in terms of operating on your vector, it appears that (technically) you could run into such a problem:
[C++11: 17.6.5.9/3]: A C++ standard library function shall not directly or indirectly modify objects (1.10) accessible by threads other than the current thread unless the objects are accessed directly or indirectly via the function’s non-const arguments, including this.
[C++11: 17.6.5.9/4]: [Note: This means, for example, that implementations can’t use a static object for internal purposes without synchronization because it could cause a data race even in programs that do not explicitly share objects between threads. —end note]
Notice that, although synchronisation is being required in this note, that's been mentioned within a passage that ultimately acknowledges that static implementation details are otherwise allowed.
That being said, it seems like the standard should further state that user code should avoid operating on standard containers during static initialisation, if the intent were that the semantics of such code could not be guaranteed; I'd consider this a defect in the standard, either way. It should be clearer.
1 And it is a NULL pointer, whatever the bit-wise representation of that may be, rather than a blot to all-zero-bits.
vector doesn't depend on anything preventing its use in dynamic initialisation of statics. The only issue with your code is a lack of thread safety - no particular reason to think you should care about that, unless you have statics whose construction spawns threads....
Initializing result (see code below) could end up calling the vector constructor before that class is fully initialized, leading to access to uninitialized memory.
No... initialising result calls AddQuery which checks if (pending == NULL) - the initialisation to NULL will certainly have been done before any dynamic initialisation, per 3.6.2/2:
Constant initialization is performed:
...
— if an object with static or thread storage duration is not initialized by a constructor call and if either the object is value-initialized or every full-expression that appears in its initializer is a constant expression
So even if the result assignment is in a different translation unit it's safe. See 3.6.2/2:
Together, zero-initialization and constant initialization are called static initialization; all other initialization is dynamic initialization. Static initialization shall be performed before any dynamic initialization takes place.
I have recently read Andrei Alexandrescu's Modern C++ Design. After reading 6. chapter, I begin to worry about our singletons at company. Since our experienced team leader writes core helper libraries like singletons etc... . I asked him if the way he handles singleton takes care of on dead reference problem ? If he used at_exit function call which is given by C core language?
He told me C++11 has singleton support and will execute CTORs and DTORs in a row that they will not be any dead reference problem. User will not have to cope with synchronization.
Even it sounds awesome I couldn't find any information which confirms him on internet. So please tell me if C++11 takes care of Dead Reference Problem for singletons and if so please explain a little what dark magic going behind ?
Presumably your team leader is talking about singletons implemented as follows:
T &get_value() {
static T val;
return val;
}
In this case, the standard gives two guarantees. The first is that the val objects will be constructed exactly once, the first time that the flow of program execution passes the declaration of the local static variable, even if that happens simultaneously on several threads 6.7/4:
An implementation is permitted to perform early initialization of other block-scope variables with static or thread storage duration under the same conditions that an implementation is permitted to statically initialize a variable with static or thread storage duration in namespace scope (3.6.2). Otherwise such a variable is initialized the first time control passes through its declaration; such a variable is considered initialized upon the completion of its initialization. If the initialization exits by throwing an exception, the initialization is not complete, so it will be tried again the next time control enters the declaration. If control enters the declaration concurrently while the variable is being initialized, the concurrent execution shall wait for completion of the initialization.
Static initialisation is only allowed in the case of constants, so as long as T does not have a constexpr constructor you shouldn't have to worry (but read 3.6.2 for the full rules, in case there is some edge case that is relevant to your code).
The second guarantee is that all variables with static storage duration will be destructed in the reverse order of their construction 3.6.3/1:
Destructors (12.4) for initialized objects (that is, objects whose lifetime (3.8) has begun) with static storage duration are called as a result of returning from main and as a result of calling std::exit (18.5). Destructors for initialized objects with thread storage duration within a given thread are called as a result of returning from the initial function of that thread and as a result of that thread calling std::exit. The completions of the destructors for all initialized objects with thread storage duration within that thread are sequenced before the initiation of the destructors of any object with static storage duration. If the completion of the constructor or dynamic initialization of an object with thread storage duration is sequenced before that of another, the completion of the destructor of the second is sequenced before the initiation of the destructor of the first. If the completion of the constructor or dynamic initialization of an object with static storage duration is sequenced before that of another, the completion of the destructor of the second is sequenced before the initiation of the destructor of the first. [Note: This definition permits concurrent destruction. — end note ] If an object is initialized statically, the object is destroyed in the same order as if the object was dynamically initialized. For an object of array or class type, all subobjects of that object are destroyed before any block-scope object with static storage duration initialized during the construction of the subobjects is destroyed. If the destruction of an object with static or thread storage duration exits via an exception, std::terminate is called (15.5.1).
While this paragraph gives a lot of scope for concurrent destruction of static objects when their construction was concurrent, the main thing to take away from it is that destruction happens in the reverse order of construction.
Together, these mean means that if T val depends on some U val in another of these singleton functions, the U val will always be constructed before T val and destructed after the T val, so overall, this is a safe way of implementing singletons (unless you're doing something very crazy).
I heard that after some version of gcc using simply something like:
static A* a = new A();
return a;
Is thread-safe for a singleton and one wouldn't need something adapted from say http://locklessinc.com/articles/singleton_pattern/ anymore...
Does anyone have a specific reference or link to where I can read about this?
Section 6.7 of draft standard (n3337.pdf), point 4:
The zero-initialization (8.5) of all block-scope variables with static storage duration (3.7.1) or thread storage
duration (3.7.2) is performed before any other initialization takes place. Constant initialization (3.6.2) of a
block-scope entity with static storage duration, if applicable, is performed before its block is first entered.
An implementation is permitted to perform early initialization of other block-scope variables with static or
thread storage duration under the same conditions that an implementation is permitted to statically initialize
a variable with static or thread storage duration in namespace scope (3.6.2). Otherwise such a variable is
initialized the first time control passes through its declaration; such a variable is considered initialized upon
the completion of its initialization. If the initialization exits by throwing an exception, the initialization
is not complete, so it will be tried again the next time control enters the declaration. If control enters
the declaration concurrently while the variable is being initialized, the concurrent execution shall wait for
completion of the initialization.88 If control re-enters the declaration recursively while the variable is being
initialized, the behavior is undefined.
GCC follows the cross-vendor Itanium C++ ABI. The relevant sections covering thread-safe initialization of function-local statics are 2.8 Initialization guard variables and 3.3.2 One-time Construction API, which says:
An implementation that does not anticipate supporting multi-threading may simply check the first byte (i.e., the byte with lowest address) of that guard variable, initializing if and only if its value is zero, and then setting it to a non-zero value.
However, an implementation intending to support automatically thread-safe, one-time initialization (as opposed to requiring explicit user control for thread safety) may make use of the following API functions:
...
There were some bugs in the early GCC implementation of that API, I think they are all fixed and it works correctly from GCC version 4.3 (possibly earlier, I don't recall and can't find a reference right now.)
However, Singleton is a bad, bad pattern, do not use it!