I am currently reading Effective C++. There is a section about using static local variables and it says that if multiple threads access a static variable, there may be a race condition during initialization of that variable.
At least that is my interpretation. Is this true? In C# for example, initialization of a class static variable will never have a race condition.
For example, can this code have a race condition during the static variable initialization?
FileSystem& tfs()
{
static FileSystem fs;
return fs;
}
Below is the except from the book.
Here's the technique applied to both tfs and tempDir:
class FileSystem { ... }; // as before
FileSystem& tfs() // this replaces the tfs object; it could static in the FileSystem class
{
static FileSystem fs; // define and initialize a local static object
return fs; // return a reference to it
}
.
class Directory { ... }; // as before
Directory::Directory( params ) // as before, except references to tfs are now to tfs()
{
...
std::size_t disks = tfs().numDisks();
...
}
Directory& tempDir() // this replaces the tempDir object; it could be static in the Directory class
{
static Directory td; // define/initialize local static object
return td; // return reference to it
}
Clients of this modified system program exactly as they used to,
except they now refer to tfs() and tempDir() instead of tfs and
tempDir. That is, they use functions returning references to objects
instead of using the objects themselves.
The reference-returning functions dictated by this scheme are always
simple: define and initialize a local static object on line 1, return
it on line 2. This simplicity makes them excellent candidates for
inlining, especially if they're called frequently (see Item 30). On
the other hand, the fact that these functions contain static objects
makes them problematic in multithreaded systems. Then again, any kind
of non-const static object — local or non-local — is trouble waiting
to happen in the presence of multiple threads. One way to deal with
such trouble is to manually invoke all the reference-returning
functions during the single-threaded startup portion of the program.
This eliminates initialization-related race conditions.
This section is outdated. The C++03 standard had no mention of threads, so when C++ implementations added them, they did whatever they wanted to with regards to the thread-safety of language constructs. A common choice was to not ensure thread-safe initialisation of static local variables.
In C++11, local static variables are guaranteed to be initialised exactly once, the first time that the program's control flow passes through their declaration, even if this happens concurrently on multiple 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.
Even so, this only ensures that initialisation is safe. If you plan to use the returned FileSystem from multiple threads simultaneously, FileSystem must itself provide threadsafe operations.
Related
For example, I have this class:
class Example
{
public:
static int m_test;
}
I have threads A and B both using this static member variable. Is this member variable thread safe somewhere under the hub?
I would assume it is not, since it is statically allocated and therefore both threads would be accessing the same memory location, possibly causing collisions. Is that correct or there is some hidden mechanism that makes this static member thread-safe?
No it is not thread safe insofar there is no built-in mechanism to obviate data races.
static std::atomic<int> m_test; would be though.
Note that you also have thread_local as a storage duration too - not of use to you in this instance - but if you had that rather than static then every thread would get their own m_test.
It is safe if both threads just read that variable. If at least one updates it, then it's a data race -> undefined behavior.
Hidden mechanism are atomic operations. E.g., via making this variable of std::atomic<int> type in C++11.
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).
(Code taken from book: http://gameprogrammingpatterns.com/ by Robert Nystrom)
In the book above the author comes with two different ways of making a singleton class:
First one:
class FileSystem
{
public:
static FileSystem& instance()
{
// Lazy initialize.
if (instance_ == NULL) instance_ = new FileSystem();
return *instance_;
}
private:
FileSystem() {}
static FileSystem* instance_;
};
And second one:
class FileSystem
{
public:
static FileSystem& instance()
{
static FileSystem *instance = new FileSystem();
return *instance;
}
private:
FileSystem() {}
};
Later he states that the second one is more proper way to do this, since it is thread safe, while the first one is not.
What makes the second one thread safe?
What is the difference in static declarations between these two?
The first version is not thread-safe for multiple threads may try to read and modify instance_ concurrently without any synchronization, which leads to a race condition.
The second version is thread-safe since C++11. Quoted from cppreference (the Static local variables section):
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)
With this guarantee, modification to instance happens only once, and there is no problem with concurrent reads.
Still, the second version is not thread-safe until C++11.
In the first code snippet setting the instance_ pointer to a singleton is an assignment. It does not get any special treatment from the compiler. In particular, it could be done multiple times if instance() is invoked from concurrent threads.
This creates a problem when two concurrent threads try evaluating instance_ == NULL, and get a true. At this point both threads create a new instance, and assign it to the instance_ variable. The first pointer assigned to instance_ is leaked, because the second thread immediately overrides it, rendering the object inaccessible.
In the second code snippet setting the instance pointer is initialization. The compiler guarantees that initialization of a static variable will be done at most once, regardless of the number of threads that invoke instance() concurrently. Essentially, the guarantee that there is at most one singleton in the system is provided by the compiler, without any explicit code for handling concurrency.
In former case, if two threads try to create the instance at the same time, 2 (or more) copies of singleton objects might be created. (if **instance_** is observed NULL by both and both create a new instance). (Even worse, thread creating first instance may get a different value of instance in subsequent calls)
While second one uses static initialization and object is constructed when the function is invoked for the first time. So it is guaranteed by the compiler that static FileSystem *instance = new FileSystem(); would be executed at most once during the lifetime of program single and thus atmist single copy of object would exist at any time.
This makes the later design thread safe for C++11 and onwards complian C++ compilers. Though the design may not be safe for in C++03 and C++98 implementation.
Another downside of former design is, the object can not be destructed while in later design it can be destructed by changing the typeof instance_ to static FileSystem. i.e.
static FileSystem& instance()
{
static FileSystem instance;
return instance;
}
Related: Is Meyers implementation of Singleton pattern thread safe?
If I have a class whose sole purpose is to have global static instances (to ensure the code in it's constructor is run before main) and it uses a class static variable, does access to this variable need to be protected via mutex?
An example will help:
class WinSock
{
public:
WinSock()
{
if(!(inst++))
//winsock init
}
~WinSock()
{
if(!--inst)
//winsock deactivate
}
private:
static int inst = 0;
}
static WinSock unusedWinSockVar;
This is all in a header that is included by any file using winsock. Does access to inst need to be protected, or is it impossible for this code to be run from multiple threads since threads will be created only once main runs and destroyed before main returns?
Firstly, I don't think that private: static int inst = 0; is a valid construct, my compilers complains loudly - if you omitted that you have something like int WinSock::inst = 0 in some .cpp file in your project for simplicity, then it's ok. If not and your project compiles at all, there is a good chance that all translation units will use a different variable, and therefore result in incorrect behavior.
Secondly, if any of the static-object constructors creates a new thread, then you need to make your code thread safe. From C++ standard p. 3.6.2:
If a program starts a thread (30.3), the subsequent initialization of
a variable is unsequenced with respect to the initialization of a
variable defined in a different translation unit. Otherwise, the
initialization of a variable is indeterminately sequenced with respect
to the initialization of a variable defined in a different translation
unit.
Indeterminate sequencing means that initialization will not have any particular ordering, but it will not overlap, so you don't need any additional safeguards. No ordering means that constructors in different compilation unis might overlap, and therefore thread safety is required.
Thirdly, do you even need it done like this? Do you have other static objects that use winsock in their constructors? I really cannot think of any other reason to do it like that.
Given the specific scenario that you describe, this is fine without adding synchronization.
Your concern is that Winsock is initialized (and de-initialized) before (after) main runs, this is guaranteed to be the case. The code is guaranteed to be only called once from one thread, too. This (the fact that there's only one thread) makes synchronization useless.
Assuming that other static global objects use Winsock (whether or not they spawn threads), that would of course be unsafe, but it wouldn't be any safer with a mutex either. The initialization takes place at an implementation-defined point in time before main.
Therefore, no static global object can use Winsock in a safe, well-defined way using this construct, since either way you don't know whether initialization occurred first. Synchronizing it doesn't change a thing for that detail.
Note: the initialization of inst inside the class declaration isn't allowed as it is.