c++ function pointer assignment is safe? - c++

Is this code thread safe?
static PFN_SOMEFUNC pfnSomeFunc = nullptr;
PFN_SOMEFUNC SomeFuncGetter();
void CalledFromManyThreads() {
if (pfnSomeFunc == nullptr)
pfnSomeFunc = SomeFuncGetter();
pfnSomeFunc();
}
This is not atomic pointer operation question. There are some special conditions.
SomeFuncGetter() always returns same address.
SomeFuncGetter() is thread safe.

It doesn't look thread-safe, because the global variable can be modified by any thread without synchronization. Even an assignment is not guaranteed to be atomic.
What you could do is leverage a language feature that guarantees thread-safe atomic initialization by moving the static into your function (a very common solution to the Static Initialization Fiasco):
void CalledFromManyThreads() {
static PFN_SOMEFUNC pfnSomeFunc = SomeFuncGetter();
pfnSomeFunc();
}
Now it's thread-safe. And if you need that cached result in multiple places, you can wrap it:
PFN_SOMEFUNC GetSomeFunc()
{
static PFN_SOMEFUNC pfnSomeFunc = SomeFuncGetter();
return pfnSomeFunc;
}
void CalledFromManyThreads() {
PFN_SOMEFUNC pfnSomeFunc = GetSomeFunc();
pfnSomeFunc();
}

Related

impact on global pointers while threads updating it

My concerns is, what will be the impact on the global pointers when accessed between the threads. My global pointer were a thread safe class. From the code what will the impact on the global pointer, when updatethread() method updating the pointer with new pointer and workerthread() accessing the pointer. What synchronization i should work with?
SomeCache* ptrCache = NULL;
//worker thread
void Workerthread(std::string strFileToWork)
{
while (std::getline(fileStream, strCurrent))
{
//worker thread accessing the global pointer
if (ptrCache->SearchValue(strCurrent))
{
iCounter++;
}
}
}
void updatethread()
{
//replace old cache with a new fresh updated.
SomeCache* ptrOldCache = ptrCache;
ptrCache = ptrNewCache;
}
One possible solution with mutexes:
std::mutex ptrCacheMutex;
SomeCache* ptrCache = null_ptr;
void Workerthread(...)
{
...
bool valueFound;
{
std::scoped_lock lk(ptrCacheMutex);
valueFound = ptrCache && ptrCache->SearchValue(...);
}
if (valueFound)
iCounter++;
...
}
void updatethread()
{
...
{
std::scoped_lock lk(ptrCacheMutex);
auto ptrOldCache = std::exchange(ptrCache, ptrNewCache);
}
...
}
If your compiler doesn't support template argument deduction, you should specify mutex type explicitly: std::scoped_lock<std::mutex> ....
The behave is probably undefined, you can refer to this answer regarding the volatile keyword in C++.
https://stackoverflow.com/a/72617/10443813
If the volatile keyword is used, before the following line is executed, the old value is used, and after, the new value is used. Otherwise the behave might be compiler or compiling flag dependent.
ptrCache = ptrNewCache;

What is the order of initializing local variables and running statements in a function (+memory order)?

For the following code, will the Lock object be initialized after or before the first statement?
int* data = NULL;
int* example() {
if (data) return data;
Lock lock;
data = new int[10];
return data;
}
I know it should work as expected in this way:
int* data = NULL;
int* example() {
if (data) return data;
{
Lock lock;
if (!data)
data = new int[10];
}
return data;
}
But do both methods above work in multiple threads on a weak memory order machine? I tried to search but couldn't find an answer.
Local variables are initialized when execution passes through the point of their definition. That is, your first implementation of example() is equivalent to (this even incorrect use of double-checked locking - it omits the second check in addition to having a data-race...):
int* example() {
if (data)
return data;
{
Lock lock; // (this really needs to reference some already initialized mutex
data = new int[10];
return data;
}
}
Assuming your Lock class acquires a suitably initialized mutex, the code still has a data-race according to the C++ standard: reading data in the if-statement and the return-statement is not synchronized with setting data later. As a result, all of these functions result in undefined behavior according to the C++ standard. A simple fix avoiding all of the problems is to rely on the guarantees for initializating function-local static variables:
int* example() {
static int* rc = new int[10];
return rc;
}
The initialization of rc has to be done in a thread-safe way. If multiple threads try to initialize rc concurrently, only one thread will manage to do so while all other threads are blocked until the initializaton is complete.

Mutex when returning object value

If I understand how C++ compilers handle local variables then IsShutdownInProgress() does not need any locking since the shutdownInProgress static variable will be placed on the stack. Am I correct?
class MyClass
{
private:
// Irrelevant code commented away
static pthread_mutex_t mutex;
static bool shutdownInProgress;
public:
static void ShutdownIsInProgress()
{
pthread_mutex_lock(mutex);
shutdownInProgress = true;
pthread_mutex_unlock(mutex);
}
static bool IsShutdownInProgress()
{
// pthread_mutex_lock(mutex);
// pthread_mutex_unlock(mutex);
return shutdownInProgress;
}
}
Am I correct?
No. This will make a copy of it to return; but reading it to make that copy without synchronisation will give a data race, with undefined behaviour. You'll need to make a local copy of it with the mutex locked:
static bool IsShutdownInProgress()
{
pthread_mutex_lock(mutex);
bool result = shutdownInProgress;
pthread_mutex_unlock(mutex);
return result;
}
or, using a less error-prone RAII lock type:
static bool IsShutdownInProgress()
{
lock_guard lock(mutex);
return shutdownInProgress;
}
In C++11, you might consider std::atomic<bool> for more convenient, and perhaps more efficient, access to simple types from multiple threads.
Race conditions are unrelated to whether a variable is located on the heap or on the stack. A race condition is when one thread is modifying a variable (a memory location) and another thread is reading or modifying the same variable. There is no guarantee that the modification of a bool is atomic so the posted code has a race condition, and therefore undefined behaviour.
A fix would be to store the value of the bool when the mutex is held and return the variable:
static bool IsShutdownInProgress()
{
pthread_mutex_lock(&mutex);
bool result = shutdownInProgress;
pthread_mutex_unlock(&mutex);
return result;
}
c++11 introduced std::mutex and std::lock_guard that could be used and the use of the lock_guard would avoid the requirement of a temporary variable to store the bool value for return:
static std::mutex mtx_;
static bool IsShutdownInProgress()
{
std::lock_guard<std::mutex> lk(mtx_);
return shutdownInProgress;
}
c++11 also introduced std::atomic<> that would ensure the modification is atomic and avoid the need for an explicit lock:
static std::atomic<bool> shutdownInProgress;
static bool IsShutdownInProgress()
{
return shutdownInProgress;
}
If c++11 is unavailable to boost::atomic was introduced in v1.53.0 and boost also has equivalent boost::mutex and boost::lock_guard.
Yes, it needs a lock
C++11's memory model states you have a data race if any threads are writing a value at the same time as another thread reading it. This is because both a read and/or a write may not be atomic.
In this case you will return a local from the function, but to get that local the compiler needs to copy the value in shutdownInProgress, which may be concurrently being changed by another thread calling ShutdownIsInProgress().
An easy way to solve this is to make shutdownInProgress an atomic:
static std::atomic<bool> shutdownInProgress;
If you make it atomic, you don't need any locks at all for either function

Thread safe singleton in C++

I have been reading about thread safe singletons and the implementation I find everywhere has a getInstance() method something like this:
Singleton* getInstance()
{
if ( !initialized )
{
lock();
if ( !initialized )
{
instance = new Singleton();
initialized = true;
}
unlock();
}
return instance;
}
Is this actually thread safe?
Have I missed something or is there a small chance this function will return an uninitialized instance because 'initialized' may be reordered and set before instance?
This article is on a slightly different topic but the top answer describes why I think the above code is not thread safe:
Why is volatile not considered useful in multithreaded C or C++ programming?
Not a good idea. Look for double check locking. For instance:
http://www.drdobbs.com/cpp/c-and-the-perils-of-double-checked-locki/184405726
http://www.drdobbs.com/cpp/c-and-the-perils-of-double-checked-locki/184405772
It is indeed not thread safe, because after the pointer gets returned you still work with it, although the mutex is unlocked again.
What you can do is making the child class which inherits from singleton, thread safe. Then you're good to go.
Below is the code for a thread-safe singleton, using Double Check and temporary variable. A temporary variable is used to construct the object completely first and then assign it to pInstance.
Singleton* Singleton::instance() {
if (pInstance == 0) {
Lock lock;
if (pInstance == 0) {
Singleton* temp = new Singleton; // initialize to temp
pInstance = temp; // assign temp to pInstance
}
}
return pInstance;
}

efficient thread-safe singleton in C++

The usual pattern for a singleton class is something like
static Foo &getInst()
{
static Foo *inst = NULL;
if(inst == NULL)
inst = new Foo(...);
return *inst;
}
However, it's my understanding that this solution is not thread-safe, since 1) Foo's constructor might be called more than once (which may or may not matter) and 2) inst may not be fully constructed before it is returned to a different thread.
One solution is to wrap a mutex around the whole method, but then I'm paying for synchronization overhead long after I actually need it. An alternative is something like
static Foo &getInst()
{
static Foo *inst = NULL;
if(inst == NULL)
{
pthread_mutex_lock(&mutex);
if(inst == NULL)
inst = new Foo(...);
pthread_mutex_unlock(&mutex);
}
return *inst;
}
Is this the right way to do it, or are there any pitfalls I should be aware of? For instance, are there any static initialization order problems that might occur, i.e. is inst always guaranteed to be NULL the first time getInst is called?
If you are using C++11, here is a right way to do this:
Foo& getInst()
{
static Foo inst(...);
return inst;
}
According to new standard there is no need to care about this problem any more. Object initialization will be made only by one thread, other threads will wait till it complete.
Or you can use std::call_once. (more info here)
Your solution is called 'double checked locking' and the way you've written it is not threadsafe.
This Meyers/Alexandrescu paper explains why - but that paper is also widely misunderstood. It started the 'double checked locking is unsafe in C++' meme - but its actual conclusion is that double checked locking in C++ can be implemented safely, it just requires the use of memory barriers in a non-obvious place.
The paper contains pseudocode demonstrating how to use memory barriers to safely implement the DLCP, so it shouldn't be difficult for you to correct your implementation.
Herb Sutter talks about the double-checked locking in CppCon 2014.
Below is the code I implemented in C++11 based on that:
class Foo {
public:
static Foo* Instance();
private:
Foo() {}
static atomic<Foo*> pinstance;
static mutex m_;
};
atomic<Foo*> Foo::pinstance { nullptr };
std::mutex Foo::m_;
Foo* Foo::Instance() {
if(pinstance == nullptr) {
lock_guard<mutex> lock(m_);
if(pinstance == nullptr) {
pinstance = new Foo();
}
}
return pinstance;
}
you can also check complete program here: http://ideone.com/olvK13
Use pthread_once, which is guaranteed that the initialization function is run once atomically.
(On Mac OS X it uses a spin lock. Don't know the implementation of other platforms.)
TTBOMK, the only guaranteed thread-safe way to do this without locking would be to initialize all your singletons before you ever start a thread.
Your alternative is called "double-checked locking".
There could exist multi-threaded memory models in which it works, but POSIX does not guarantee one
ACE singleton implementation uses double-checked locking pattern for thread safety, you can refer to it if you like.
You can find source code here.
Does TLS work here? https://en.wikipedia.org/wiki/Thread-local_storage#C_and_C++
For example,
static _thread Foo *inst = NULL;
static Foo &getInst()
{
if(inst == NULL)
inst = new Foo(...);
return *inst;
}
But we also need a way to delete it explicitly, like
static void deleteInst() {
if (!inst) {
return;
}
delete inst;
inst = NULL;
}
The solution is not thread safe because the statement
inst = new Foo();
can be broken down into two statements by compiler:
Statement1: inst = malloc(sizeof(Foo));
Statement2: inst->Foo();
Suppose that after execution of statement 1 by one thread context switch occurs. And 2nd thread also executes the getInstance() method. Then the 2nd thread will find that the 'inst' pointer is not null. So 2nd thread will return pointer to an uninitialized object as constructor has not yet been called by the 1st thread.