PDA

View Full Version : Atomics: reordering and memory semantics



mentalmushroom
20th October 2016, 08:02
I'm now trying to find my feet in lock-free programming. In particular I am curious about possible reordering for different memory semantics.

Consider the following example. There are two threads (producer and consumer). Release-acquire memory order is used for synchronization.


#include <QCoreApplication>
#include <QDebug>
#include <QtConcurrent>

QAtomicPointer<QString> ptr;
int data;

void producer()
{
QString* p = new QString("Hello");
data = 42;
ptr.storeRelease(p);
}

void consumer()
{
QString* p2;
//while (!(p2 = ptr.load())) // ?
while (!(p2 = ptr.loadAcquire()))
;
Q_ASSERT(*p2 == "Hello"); // never fires
Q_ASSERT(data == 42); // never fires
}


int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QtConcurrent::run(producer);
QtConcurrent::run(consumer);
return a.exec();
}


I'm wondering why it is necessary to use release-acquire semantics here? What might happen if we used the relaxed load in consumer?

anda_skoa
20th October 2016, 17:27
Why would the first assert be hit?

You wait for p2 to be not null, which means producer has stored the pointer to its string. Which has the content that you are asserting on.

The second assert could be hit is the write to data is reordered to after the setting of ptr and the other thread successfully loads from ptr before data has been written to, flushed to memory and synchronized into the cache of the second thread's execution unit.

Assuming that there is more than one thread.

Cheers,
_

mentalmushroom
20th October 2016, 18:13
You wait for p2 to be not null, which means producer has stored the pointer to its string. Which has the content that you are asserting on.
I don't understand. When p gets stored it's already initialized to new string("hello") and, as far as I understand, initialization of p can't be reordered past the store call as long as p is the argument (i.e. the store call depends on p). Or do you mean that only the pointer address is available, but the pointed data may be not synchronized?


The second assert could be hit is the write to data is reordered to after the setting of ptr and the other thread successfully loads from ptr before data has been written to, flushed to memory and synchronized into the cache of the second thread's execution unit.
Shouldn't ptr.storeRelease() prevent it from being reordered?

anda_skoa
20th October 2016, 21:19
I don't understand. When p gets stored it's already initialized to new string("hello") and, as far as I understand, initialization of p can't be reordered past the store call as long as p is the argument (i.e. the store call depends on p).

Exactly, hence it being impossible that the assert condition would not be true.



Shouldn't ptr.storeRelease() prevent it from being reordered?

That's the question, does that memory barrier effect other writes than the one it is protecting?

Cheers,
_

mentalmushroom
21st October 2016, 06:33
Exactly, hence it being impossible that the assert condition would not be true.
Not sure if we are talking about the same thing. I mean what if relaxed order were used instead of acquire? Would it be unsafe to dereference the pointer in that case?


That's the question, does that memory barrier effect other writes than the one it is protecting?
If I understand it correctly, yes, but only if the other thread uses acquire (or stronger) to load the atomic variable. Otherwise, it may not see updates for non-atomic variables made by the release thread.