Atomic data member calling from a thread - c++

Can someone please help me understand what i am doing wrong here?
When i make the data members of the class non atomic it is working fine.
class AtomicTest
{
atomic<int> A{ 0 };
atomic<int> B{ 0 };
public :
AtomicTest() { }
void func1()
{
A = 1;
cout << "func1 " << A << endl;;
}
void func2()
{
cout << "func2 " << A << endl;
A = A + 1;
cout << A << endl;
}
};
int main()
{
AtomicTest a;
thread t1(&AtomicTest::func1, std::ref(a)); // I tried to move as well, i know ref would share data between two threads but i can use mutex to protect data if its needed but i cannot even call the func1
//thread t2(&AtomicTest::func2, std::ref(a));
t1.join();
//t2.join();
return 0;
}

Due to concurrency without additional synchronization in this case it's impossible to predict program behavior:
A = A + 1;
This simple line consists of 1 atomic load and 1 atomic store operations. Even default memory order (std::memory_order_seq_cst) wont give you any guarantees about mixed simultaneous execution of these two threads. Standard says such case has an undefined behavior -- there is data race for your variable (it doesn't matter is it atomic or not).
Try to add some lock primitives (such as std::mutex) or change the logic to use special atomic functions (such as fetch_add, exchange etc.). See more at the cpp-reference.

Related

Scoped lock_guard Not Releasing Mutex in Static Method

Platform Debian 9 | ARM
I have a class that is used to store thread IDs on a std::list and then print the list as part of the shutdown procedure. There are two static methods: AddId() and PrintIds(). Since the static methods are used by several threads, the list access is protected with a std::mutex. I have come across two issues that have me baffled and they may be related. I hope one of you can help explain what I am missing.
Note I first used scoped std::lock_guard<std::mutex>s and have temporarily settled on the std::unique_lock<std::mutex>s that are shown in the code for the reasons explained herein.
Issue 1 When the program starts, all threads call ThreadMgr::AddId(), which adds the thread id to the list along with a string name. That seems to work fine. However, when ThreadMgr::PrintIds() is called during the shutdown procedure, the std::mutex is still locked and the std::lock_guard blocks. While testing, I unlocked the std::mutex in the line preceding the std::lock_guard--which is undefined behavior if it wasn't locked by the calling thread--and then it worked as expected. The only place the std::mutex is used is in these two methods, and with the std::lock_guard being scoped, the std::mutex should have been unlocked with every method call. I went through several iterations of locking and unlocking the std::mutex directly, using std::unique_locks, etc. I eventually found a somewhat workable solution using the std::unique_locks that are in the code provided here. However, that too has me baffled.
The std::unique_locks work if I use std::adopt_lock, but only in ThreadMgr::PrintIds(). If I use std::adopt_lock in ThreadMgr::AddId(), then I get a segmentation fault whenever ThreadMgr::PrintIds() is called.
Issue 2 As previously stated, ThreadMgr::AddId() runs fine with either std::lock_guard or std::unique_lock when all threads call it on startup. However, there are UI sessions where each session spawns a thread. When ThreadMgr::AddId() is called from one of these session threads, both std::lock_guard and std::unique_lock block like the std::mutex is already locked. So, ThreadMgr::AddId() works perfectly fine for every other thread, but not for the session threads that are started later.
If there is any other information I can provide to help get to a solution, let me know.
class ThreadMgr {
public:
ThreadMgr();
~ThreadMgr();
static void AddId(std::string);
static void PrintIds();
private:
static std::list<ThreadId> t_list;
static std::mutex list_mtx;
};
/*Definition*/
ThreadMgr::ThreadMgr() {}
ThreadMgr::~ThreadMgr() {}
/*Static Members*/
void ThreadMgr::AddId(std::string name) {
ThreadId t_id = getThreadId(name);
{
std::unique_lock<std::mutex> lock(list_mtx);
t_list.push_front(t_id);
}
std::lock_guard<std::mutex> lk(cout_mtx);
std::cout << "---Added id: " << t_id.tid << " for the " << name << " thread." << std::endl;
return;
}
void ThreadMgr::PrintIds() {
std::ostringstream oss;
oss << "\n**************************Thread Ids**************************\n";
{
std::unique_lock<std::mutex> lock(list_mtx, std::adopt_lock);
for (std::list<ThreadId>::iterator t = t_list.begin(); t != t_list.end(); t++) {
oss << "---" << t->name << " : " << t->tid << '\n';
}
}
oss << "************************End Thread Ids************************" << '\n';
std::lock_guard<std::mutex> lk(cout_mtx);
std::cout << oss.str() << std::endl;
return;
}
std::mutex ThreadMgr::list_mtx;
std::list<ThreadId> ThreadMgr::t_list;
int Main(){
ThreadMgr::AddId("Main");
std::thread MbServerT(MbServer);
std::thread UiServerT(UiServer);
while(run){
//do stuff
}
ThreadMgr::PrintIds();
if(MbServerT.joinable())
MbServerT.join();
if(UiServerT.joinable())
UiServerT.join();
return 0;
}

How to implement simple custom lock using acquire-release memory order model?

I'm trying to understand acquire-release memory order through implementing my custom lock.
#include <atomic>
#include <vector>
#include <thread>
#include <iostream>
class my_lock {
static std::atomic<bool> flag;
public:
void lock() {
bool expected = false;
while (!flag.compare_exchange_strong(expected, true, std::memory_order_acq_rel))
expected = false;
}
void unlock() {
flag.store(false, std::memory_order_release);
}
};
std::atomic<bool> my_lock::flag(false);
static int num0 = 0;
static int num1 = 0;
my_lock lk;
void increase() {
for(int i = 0; i < 100000; ++i) {
lk.lock();
num0++;
num1++;
lk.unlock();
}
}
void read() {
for(int i = 0; i < 100000; ++i) {
lk.lock();
if(num0 > num1) {
std::cout << "num0:" << num0 << " > " << "num1:" << num1 << std::endl;
}
lk.unlock();
}
}
int main() {
std::thread t1(increase);
std::thread t2(read);
t1.join();
t2.join();
std::cout << "finished! num0:" << num0 << ", num1:"<< num1 << std::endl;
}
Question 1: Am I correct to use acquire-release memory order ?
Below are paragraph from C++ Concurrency In Action
Despite the potentially non-intuitive outcomes, anyone who’s used locks has had to deal with the same ordering issues: locking a mutex is an acquire operation, and unlocking the mutex is a release operation. With mutexes, you learn that you must ensure that the same mutex is locked when you read a value as was locked when you wrote it, and the same applies here; your acquire and release operations have to be on the same variable to ensure an ordering. If data is protected with a mutex, the exclusive nature of the lock means that the result is indistinguishable from what it would have been had the lock and unlock been sequentially consistent operations. Similarly, if you use acquire and release orderings on atomic variables to build a simple lock, then from the point of view of code that uses the lock, the behavior will appear sequentially consistent, even though the internal operations are not.
This paragraph says that "the result is indistinguishable from ..... sequentially consistent operation".
Question 2: Why the result is indistinguishable? If we use lock, the result should be distinguishable from my understanding.
Edit :
I add one more question.
Below is std::atomic_flag example in C++ concurrency in action.
class spinlock_mutex
{
std::atomic_flag flag;
public:
spinlock_mutex():
flag(ATOMIC_FLAG_INIT)
{}
void lock()
{
while(flag.test_and_set(std::memory_order_acquire));
}
void unlock()
{
flag.clear(std::memory_order_release);
}
}
Question 3: Why does this code doesn't use std::memory_order_acq_rel? flag.test_and_set is RWM operation, so I think it should be used with std::memory_order_acq_rel like my first example.
The acquire/release is strong enough to confine the instructions within the critical sections. And it provides sufficient synchronization such that a happens before relation is established between a release of a lock and subsequent acquire of the same lock.
The lock will give you some sequential order on the lock acquire/release operations; just as with sequential consistency.
Why are you using compare_exchange_strong? You are already in a loop. You can use compare_exchange_weak.

Synchronize object

Having object that has extensive API list.
What is the best way to synchronize this object, i.e. the object already exists in legacy code and used in hundreds of lines of code.
The naive way is to wrap each API call to object with std::mutex. Is there an easier or elegant way to do it?
I have tried below code, however would like to get opinion on it or alternative solutions .
Below is template wrapper class that lock the object during the usage , in an automatic way. i.e. locks the object on creation and unlocks upon destruction.
This pattern is very similar to scope lock, however it's useful only for static objects/singletons, it wouldn't work for different instances of a given object
template <typename T> class Synced
{
static std::mutex _lock;
T& _value;
public:
Synced(T& val) : _value(val)
{
std::cout << "lock" << endl;
_lock.lock();
}
virtual ~Synced()
{
std::cout << "unlock" << endl;
_lock.unlock();
}
T& operator()()
{
return _value;
}
};
template <class T> std::mutex Synced<T>::_lock;
example class to be used with Synced template class
this could be example of a class mentioned above with tens of API's
class Board
{
public:
virtual ~Board() { cout << "Test dtor " << endl; }
void read() { cout << "read" << endl; }
void write() { cout << "write" << endl; }
void capture() { cout << "capture" << endl; }
};
example of usage , basic calls , the Synced object isn't bounded to scope , thus the destructor is called immediately after semicolon
int main(int argc, char* argv[])
{
Board b;
Synced<Board>(t)().read();
cout <<" " << endl;
Synced<Board>(t)().write();
cout << " " << endl;
Synced<Board>(t)().capture();
cout << " " << endl;
return 1;
}
Here below is output of above example run :
lock
read
unlock
lock
write
unlock
lock
capture
unlock
Test dtor
I only use mutexes for very small critical sections, a few lines of code maybe, and only if I control all possible error conditions. For a complex API you may end up with the / a mutex in an unexpected state. I tend to tackle this sort of thing with the reactor pattern. Whether or not that is practical depends on whether or not you can reasonably use serialization / deserialization for this object. If you have to write serialization yourself then consider things like API stability and complexity. I personally prefer zeromq for this sort of thing when using it is practical, your mileage may vary.

Does wrapping a std::atomic_flag in a getter/setter void its "atomicity"?

Say I have a class that contains a std::atomic_flag as private member, exposed through a getter. Something like the following (pseudo-code):
class Thing
{
private:
std::atomic_flag ready = ATOMIC_FLAG_INIT;
public:
isReady()
{
return ready.test_and_set();
}
}
My naive question is: does querying the flag through a method turn it into a non-atomic operation, being a function call non-atomic (or is it?)? Should I make my ready flag a public member and querying it directly?
No, it doesn't. The test_and_set() operation itself is atomic, so it doesn't matter how deep different threads' call-stacks are.
To demonstrate this, consider the base case where the atomic_flag object is "exposed" directly:
static atomic_flag flag = ATOMIC_FLAG_INIT;
void threadMethod() {
bool wasFirst = !flag.test_and_set();
if( wasFirst ) cout << "I am thread " << this_thread::get_id() << ", I was first!" << endl;
else cout << "I am thread " << this_thread::get_id() << ", I'm the runner-up" << endl;
}
If two threads enter threadMethod - with one thread (t1) slightly before the other (t2) then we can expect the console output to be the following (in the same order):
I am thread t1, I was first!
I am thread t2, I'm the runner-up
Now if both threads enter simultaneously, but t2 is a microsecond ahead of t1, but t2 then becomes slower than t1 as it writes to stdout, then the output would be:
I am thread t1, I'm the runner-up
I am thread t2, I was first!
...so the call to test_and_set was still atomic, even though the output is not necessarily in the expected order.
Now if you were to wrap flag in another method (not inlined, just to be sure), like so...
__declspec(noinline)
bool wrap() {
return !flag.test_and_set();
}
void threadMethod() {
bool wasFirst = wrap();
if( wasFirst ) cout << "I am thread " << this_thread::get_id() << ", I was first!" << endl;
else cout << "I am thread " << this_thread::get_id() << ", I'm the runner-up" << endl;
}
...then the program would not behave any differently - because the false or true return bool value from test_and_set() will still be in each thread's stacks. Ergo, wrapping a atomic_flag does not change its atomicity.
The atomicity property of C++ atomics guarantees that an operation can not be broken in the middle. That is, for a second thread observing the atomic, it will either observe the state before the test_and_set or the state after the test_and_set. It is not possible for such a thread to sneak in a clear between the test and the set part.
However, this is only true for the operation itself. As soon as the test_and_set call has completed, all bets are off again. You should always assume that the thread executing the test_and_set might get pre-empted immediately after finishing that instruction, so you can not assume that any instruction executing after the test_and_set will still observe the same state.
As such, adding the function call does not get you into trouble here. Any instruction following the atomic one must assume that the state of the atomic variable could have changed in the meantime. Atomics take this into account by providing interfaces that are designed in a special way: For example, test_and_set returning the result of the test, because obtaining that information through a separate call would not be atomic anymore.
No, the isReady() method would work exactly the same as direct test_and_set() call, that is atomically.

Passing an object to two std::threads

If I create an object which is going to be accessed by two different std::threads, do I need to make any special provisions when I create the object or pass it to the threads?
For example:
class Alpha
{
public:
int x;
};
void Foo(Alpha* alpha)
{
while (true)
{
alpha->x++;
std::cout << "Foo: alpha.x = " << alpha->x << std::endl;
}
}
void Bar(Alpha* alpha)
{
while (true)
{
alpha->x++;
std::cout << "Bar: alpha.x = " << alpha->x << std::endl;
}
}
int main(int argc, char * argv[])
{
Alpha alpha;
alpha.x = 0;
std::thread t1(Foo, &alpha);
std::thread t2(Bar, &alpha);
t1.join();
t2.join();
return 0;
}
This compiles fine, and seems to run fine too. But I haven't explicitly told my program that alpha needs to be accessed by two different threads. Should I be doing this differently?
You have race condition on alpha.x, as both threads may write when the other read/write its value. You may fix that by changing type of x into std::atomic<int> or by using protecting read/write access by mutex.
If an object is going to be accessed by multiple threads, then you must make provisions for synchronization. In your case, it will suffice to declare the variable x as an atomic:
#include <atomic>
class Alpha
{
public:
std::atomic<int> x;
};
This will guarantee that any function which increments "x" will actually use the atomic fetch_and_add() method. This guarantees that each thread that increments the variable "x" will get a unique incremented value of x.
In the code you have posted, it is extremely possible that both threads will get a value of 1 for x if the executions interleave just right.