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!