问题
Suppose there is a function (member function possibly)
SomeType foo()
{
static SomeType var = generateVar();
return var;
}
How var
will be initialised if foo
will be called 'for first time' from multiple threads simultaneously?
- Is it guaranteed that
generateVar()
will be called only once in any scenario (if used of course)? - Is it guaranteed that
foo
will return the same value when called multiple times in any scenario? - Is there a difference in behaviour for primitive or non-primitive types?
回答1:
Concerning C++03:
The abstract machine defined by the C++03 Standard does not contain a formal definition of what a thread is, and what the outcome of a program should be if an object is accessed concurrently.
There is no notion of synchronization primitive, ordering of operations performed in different threads, data race, and so on. Therefore, by definition, every multi-threaded C++03 program contains undefined behavior.
Of course, in practice implementations do provide a documented behavior, but there is nothing in the Standard that specifies what this behavior should be. Therefore, I would say it depends on your compiler.
The rest of the answer will focus on C++11, which does define the semantics of concurrent operations.
Concerning C++11:
Is it guaranteed that
generateVar()
will be called only once in any scenario (if used of course)?
No, not in any scenario.
The initialization of var
is guaranteed to be thread-safe, so generateVar()
won't be entered concurrently, but if an exception is thrown by generateVar()
, or by the copy constructor or move constructor of SomeType
(if SomeType
is a UDT, of course), then initialization will be re-attempted the next time the flow of execution enters the declaration - which means generateVar()
will get called again.
Per paragraph 6.7/4 of the C++11 Standard on the initialization of block-scope variables with static storage duration:
[...] 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. If control re-enters the declaration recursively while the variable is being initialized, the behavior is undefined. [...]
Concerning your next question:
Is it guaranteed that foo will return the same value when called multiple times in any scenario?
If it will manage to return a value (see above), then yes.
Is there a difference in behaviour for primitive or non-primitive types?
No, there isn't, except that there is no such a thing as a copy constructor or move constructor for primitive types, so there is also no risk that copy-initialization will result in throwing an exception (unless of course generateVar()
throws).
来源:https://stackoverflow.com/questions/16734966/static-local-variable-initialisation-in-multithreaded-environment