In the following scenario:
HeavyInitClass* f()
{
static HeavyInitClass* heavy = new HeavyInitClass();
return heavy;
}
I know that in C++11 heavy will be initialized exactly once in a multithreaded environment because the flag that marks that heavy was not initialized is thread-safe.
BUT does it also block the threads until heavy has been initialized?
If 100 threads call f() in the same time, does the 99 other threads wait until the initializing thread finishes the initialization?
Thanks a lot!
This is mandated by §6.7 [stmt.dcl]/p4 of the standard:
If control enters the declaration concurrently while the variable is being initialized, the concurrent execution shall wait for completion of the initialization.
In other words, yes. The other threads must block until initialization is complete.
Related
I have this simple function:
bool foo(const std::string& str)
{
static const std::string ky[] = { "KeyWord1", "KeyWord2", "KeyWord3" };
static const std::set<std::string> kySet(ky, ky+ sizeof(ky)/sizeof(ky[0]));
return kySet.find(str) != kySet.end();
}
It basically holds a set of pre-set keywords, and test if a given string is one of the keywords.
I use static because I want only one copy of the pre-set variables.
This will run in a multi-thread environment and on different architectures. However, I was told this is only thread-safe on Linux but will break on AIX and Solaris.
I couldn't understand why it would break?
Quoting from the 03 standard
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1905.pdf
section 6.7
An implementation is permitted to perform early initialization of
other local objects with static storage duration under the same
conditions that an implementation is permitted to statically
initialize an object with static storage duration in namespace scope
(3.6.2). Otherwise such an object is initialized the first time
control passes through its declaration; such an object is considered
initialized upon the completion of its initialization.
There is no mention of threads; and as such you should consider function statics not thread safe unless the function had been called while single threaded.
That can only be true if the compiler does not implement the C++ standard. Otherwise thread-safe dynamic initialization of variables with static storage duration is guaranteed by the standard, see [stmt.dcl].
Dynamic initialization of a block-scope variable with static storage duration or thread storage duration is performed 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. [...]
(Emphasis is mine)
It may sound dummy but,Am sort of confused, I have gone through this question,when looking into it we both where in the same situation it seems, I have to make my map as static so it will be common to all instances that will be created in separate threads and I want to synchronize the functions that gonna act on my map, so i thought of making a std::mutex as static in my class like what was suggested as an answer in the given link.. in this case will there be any race-condition occur for acquiring and locking the mutex itself? is there any better way we can synchronize the functions on static map using mutex
Does Making std::mutex as static creates race-condition for the mutex
itself
No, a Mutex isn't vulnerable to race-conditions. And as for initializing it as static, you are safe.
$6.7: 4: Dynamic initialization of a block-scope variable with static storage duration ([basic.stc.static]) or thread storage
duration ([basic.stc.thread]) is performed 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
You said:
i thought of making a std::mutex as static in my class like what was
suggested as an answer in the given link.
Do that if you are trying to protect static class member variables as well. Otherwise, make it a mutable member. The fact that you said the map will be globally initialized as static is okay, since the mutex as a member variable, will follow suite.
class Map{
public:
Map(...){}
std::size_t size() const{
std::lock_guard<std::mutex> lck(m_m);
return m_size;
}
iterator add(....) {
std::lock_guard<std::mutex> lck(m_m);
....
return your_iterator;
}
...etc
private:
mutable std::mutex m_m; //FREE ADVICE: Use a std::recursive_mutex instead
...others
};
Now:
//Somewhere at global scope:
Map mp(... ...);
// NOTES
// 1. `mp` will be initialized in a thread safe way by the runtime.
// 2. Since you've protected all Read or Write member functions of the class `Map`,
// you are safe to call it from any function and from any thread
No.
Mutexes (and other synchronisation primitives) are implemented using support from the operating system. That's the only way that they can do their job.
A direct corollorary of their ability to perform this job is that they are themselves not prone to race conditions — locking and unlocking operations on mutexes are atomic.
Otherwise, they wouldn't be much use! Every time you used a mutex, you'd have to protect it with another mutex, then protect that mutex with another mutex, and so on and so forth until you had an infinite number of mutexes, none of them actually achieving anything of any use at all. :)
The std::mutex object having static storage duration doesn't change this in any way. Presumably you were thinking of function-static variables (that, assuming they're not already immune to race conditions, must be synchronised because they may be accessed concurrently by different threads; but still, ideally you wouldn't use them at all because they make functions not be re-entrant).
I just read this article about the actual reasons behind the current boost::mutex implementation and noticed the following phrase:
Block-scope statics have the additional problem of a potential race
condition on "the first time through", which can lead to the
destructor being run multiple times on popular compilers, which is
undefined behaviour — compilers often use the equivalent of a call to
atexit in order to ensure that destruction is done in the reverse
order of construction, and the initialization race that may cause the
constructor to be run twice may also cause the destructor to be
registered twice
Is it true? Should I really check whether another thread already inside this object's destructor via atomic operations or something like this? Should I do it even in C++11 - C++14? Because as far as I know there's no more "constructor for the same local object with static storage duration can be called simultaneously from several threads" problem since C++11 -- it requires that another threads should wait for the constructor's completion. Am I right?
It looks like this article was written pre C++11, it says amongst other things:
[...] next version of the C++ Standard, scheduled to be released in 2009.[...]
and this was the case pre C++11, it was unspecified what happened in this case since threading was not part of memory model pre C++11.
This changed in C++11 and the draft C++11 standard section 6.7 Declaration statement says (emphasis mine):
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. [...] 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. [...]
Pre C++11 we have to treat the static local variable just like we treat any other critical section. We can find a excellent description of the situation pre C++11 in the post C++ scoped static initialization is not thread-safe, on purpose!.
Is this singleton thread safe for the pre-C++11 compilers ?
As we know for C++11 it is thread safe.
class Singleton
{
private:
Singleton(){};
public:
static Singleton& instance()
{
static Singleton INSTANCE;
return INSTANCE;
}
};
In C++11 what makes this thread safe is the following from the draft C++11 standard section 6.7 Declaration statement which says (emphasis mine):
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. [...] 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. [...]
while pre C++11 section 6.7 says:
[...]Otherwise such an object is initialized the first time control passes
through its declaration; such an object 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.[...]
which does not have the same guarantee that C++11 has and so it would seem pre C++11 it is not specified and therefore you can not count on it. Although this does not prevent implementations from making stronger guarantees.
This make sense since pre C++11 the memory model did not including threading.
Given:
void getBlah() {
static Blah* blah = new Blah();
return blah;
}
In a multi threaded setting, is it possible that new Blah() is called more than once?
Thanks!
The C++ standard makes no guarantee about the thread safety of static initializations - you should treat the static initialization as requiring explicit synchronisation.
The quote Alexander Gessler gives:
If control enters the declaration
concurrently while the object is being
initialized, the concurrent execution
shall wait for completion of the
initialization
is from the C++0x draft, and doesn't reflect the current C++ standard or the behaviour of many C++ compilers.
In the current C++ standard, that passage reads:
If control re-enters the declaration (recursively) while the object is being
initialized, the behaviour is undefined
No. But note that the pointer to Blah is static.
6.7 Declaration statement
4 [...] Otherwise such an object is
initialized the first time control
passes through its declaration; such
an object 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
EDIT: This pertains to the C++0x draft.
Quoting the standard (6.7-4):
If control enters the declaration concurrently
while the object is being initialized, the concurrent execution shall wait for completion of the initialization
To my understanding, static initialization like this is thread-safe.