I am pretty new to C++ and have to do some exercises on atomic operations. I am implementing a AtomicHashSet - but I get confused by compare_and_exchange_strong()
behaving different than I would expect it.
As internal data structure I use an array of std::atomic-instances:
std::atomic<Item<T>> data[N] = {};
The essential part observing the problems is the following:
bool insert(const T &key) {
if (keysStored.load() == N) {
return false;
}
size_t h = this->hash(key);
for (size_t i = 0; i < N; i++) {
size_t pos = (h + i) % N;
data[pos].load(); //No idea why that is needed...
Item<T> atPos = data[pos].load();
if (atPos.dataRef == &key) {
return false;
}
if (atPos.dataRef == nullptr && atPos.state == BucketState::Empty) {
Item<T> atomDesired(&key, BucketState::Occupied);
if (data[pos].compare_exchange_strong(atPos, atomDesired)) {
keysStored++;
return true;
}
}
}
return false;
}
Item
is defined like this:
enum class BucketState { Empty, Occupied, Deleted };
template<typename T>
struct Item {
Item(): dataRef(nullptr), state(BucketState::Empty) {}
Item(const T* dataRef, BucketState state) : dataRef(dataRef), state(state) {}
const T* dataRef;
BucketState state;
};
I do some assertion tests (inserting an element twice, checking keyStored
etc.). With this code they succeed - but if I remove the nonsense data[pos].load();
call they fail due to compare_exchange_strong()
returning false
. This strange failing behavior occurs only the first time the function is called...
I also checked with a debugger - the value of atPos is the same as in data[pos]
- so in my understanding ces should do the exchange and returjn true
.
Another question: Do I have to use a special memory order to ensure atomic (and therefore threadsafe) behaviour?
Aucun commentaire:
Enregistrer un commentaire