I am trying a very basic test with the atomic variable in c++:
this is a basic header:
#pragma once
#include<atomic>
class spinlock_mutex {
std::atomic_flag flag;
public:
spinlock_mutex() : flag(ATOMIC_FLAG_INIT) {}
void lock() {
while (flag.test_and_set())
;
}
void unlock() { flag.clear(); }
};
Here is a very basic implementation of a queue which is on purpose oversized to contain all the samples:
template <class T, uint32_t MAX_SIZE = UCHAR_MAX>
class SingleQueue {
protected:
T _q[MAX_SIZE]{};
uint16_t _back {};
int16_t _front = 0;
uint16_t _count = 0;
spinlock_mutex mtx{};
public:
SingleQueue() = default;
void push(T &&val) {
mtx.lock();
_q[_count] = std::move(val);
_count++;
mtx.unlock();
}
void push(T &val) {
mtx.lock();
_q[_count] = val;
_count++;
mtx.unlock();
}
void pop(T &val) {
mtx.lock();
val = _q[_count];
_back++;
mtx.unlock();
}
And this is my source code:
class DummyComm {
public:
int l_val1{};
int l_val2{};
};
cu::SingleQueue<DummyComm,200000> q{};
DummyComm val{};
spinlock_mutex spin {};
void producer_m() {
uint16_t count = 0;
for (int32_t idx = 0; idx < 100000; idx++) {
std::cout<<"Tx: "<<idx<<"\n";
q.push(DummyComm{idx,idx});
}
}
void consumer_m() {
std::vector<DummyComm> vec{};
DummyComm res {};
while(true)
{
q.pop(res);
std::cout<<"Rx: "<<res.l_val1<<"\n";
vec.push_back(res);
if(vec.back().l_val1==99999)
{
break;
}
}
std::cout<<vec.back().l_val1<<std::endl;
}
TEST(testOne, basic) {
std::thread prod{(producer_m)};
std::thread cons{(consumer_m)};
prod.join(), cons.join();
}
I can't manage to store all the values I need in the array, it seems the reader is slower than the writer.
If I don't use an array but a single element to store the data, everything seems to go fine.
My understanding is that atomic variable should be updated at least on an x86 architecture (which I am currently using with g++ 9.4 on Linux), therefore count which is in a critical section between a lock/unlock of a spinlock should be updated.
Any word of advice? Thanks!