It is the following piece of code
#include <memory>
#include <iostream>
#include <atomic>
class A
{
public:
A * get()
{
if(nullptr == ptr.load(std::memory_order_acquire))
{
ptr.store(new A(),std::memory_order_release);
}
return ptr.load(std::memory_order_acquire);
}
inline static std::atomic<A*> ptr = nullptr;
};
int main()
{
return 0;
}
Reading some documents the code above does not guaranteed that the ptr is not null when get is called . Actually the problem is when ThreadA check that ptr is null enter in CS and before call store ThreadB , enters in CS , allocation memory and returns. When threadA stores the values overwrite the previous one value. When get return the ptr is null. My question is why thread A does not see the updated value ?
To make the posted code thread safe, you have to use a mutual exclusion mechanism for the allocation in addition to a std::atomic
for the pointer. The most common choice would be locking a std::mutex
. Here is what that code might look like,
class AMutex
{
public:
AMutex * get()
{
if (auto p = ptr.load(); p)
return p;
std::lock_guard lock(mtx);
if (not ptr.load())
ptr.store(new AMutex());
return ptr.load();
}
inline static std::atomic<AMutex*> ptr = nullptr;
static std::mutex mtx;
};
As an aside, the code you posted looks very close to a Singleton
except that the get
function is not static
. If a Singleton
is the goal, here is a simple, thread-safe, standards-compliant option,
class A2 {
public:
static A2 *get() {
static A2 instance;
return &instance;
};
};