I have a bunch of threads. They should access a singleton containing configuration data which is initialized once when the singleton is created. Hence on the first access. So further actions on the singleton are just read-only. Do I need critical sections in this case?
It appears that because the data is created lazily on first access, the pointer or the reference to your singleton is read-write. This means that you do need a critical section.
In fact, the desire to avoid a critical section while keeping the lazy initialization in this situation has been so universally strong that it lead to the creation of the double-checked locking antipattern.
On the other hand, if you were to initialize your singleton eagerly before the reads, you would be able to avoid a critical section for accessing an immutable object through a constant pointer / reference.
No. If you're simply reading this data after it is fully initialized and the data never changes then there is no possibility of a race condition occurring.
However, if the data is written to/modified in any way then you will need to synchronize access to it, i.e., lock the data before writing.
If you only ever read some shared data, and never write, you do not need to synchronize access.
You only need to synchronize when a shared piece of data is both read and written at potentially the same time.
I understand your question as there is lazy initialization in your singleton. It is initialized only for the first read.
The next consecutive reads are thread safe. But what about concurrent read during initialization?
If you have situation like this:
SomeConfig& SomeConfig::getInstance()
{
static SomeConfig instance;
return instance;
}
Then it depends on your compiler. According to this post in C++03 it was implementation dependent if this static initialization is thread safe.
For C++11 it is thread safe - see answers to this post, citation:
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 control enters the declaration concurrently while the variable is being initialized, the concurrent execution shall wait for completion of the initialization.
It is worth to note that read only access to global variables is thread safe.
The official rule in the spec is that a data race is when one thread can write to a variable concurrently while another thread read or writes the same variable.
If you can prove that the initialization has to take place before any of the readers can read, then you do not need synchronization. This is most often accomplished by initializing before creating (or synchronizing) the threads, or by using static storage variables, which C++11 guarantees some synchronization on
© 2022 - 2024 — McMap. All rights reserved.