#pragma once
#include <vector>
#include <>
const int default_cap = 5;
template <class T>
class RingQueue
{
public:
RingQueue(int max_cap = default_cap) : _rq(max_cap), _max_cap(max_cap), _p_step(0), _c_step(0)
{
// Semaphore initialization
sem_init(&_space_sem, 0, _max_cap);
sem_init(&_data_sem, 0, 0);
//Initialize the lock
pthread_mutex_init(&_c_mtx , nullptr);
pthread_mutex_init(&_p_mtx , nullptr);
}
// Get semaphore
void P(sem_t &sp)
{
sem_wait(&sp);
}
// Release the semaphore
void V(sem_t &sp)
{
sem_post(&sp);
}
// Insert operation
void Push(const T &t)
{
// Get the space semaphore --
P(_space_sem);
//Critical area lock
pthread_mutex_lock(&_p_mtx );
_rq[_p_step] = t;
_p_step++;
_p_step %= _max_cap;
//Unlock
pthread_mutex_unlock(&_p_mtx);
// Release semaphore ++
V(_data_sem);
}
// Get the operation
void Pop(T *t)
{
// Get resource semaphore
P(_data_sem);
pthread_mutex_lock(&_c_mtx);
*t = _rq[_c_step];
_c_step++;
_c_step %= _max_cap;
pthread_mutex_unlock(&_c_mtx);
// Release the semaphore
V(_space_sem);
}
~RingQueue()
{
// Destroy the corresponding semaphore!
sem_destroy(&_space_sem);
sem_destroy(&_data_sem);
//Release the lock
pthread_mutex_destroy(&_c_mtx);
pthread_mutex_destroy(&_p_mtx);
}
private:
// The underlying linear structure simulates the ring queue
std::vector<T> _rq;
// Maximum capacity
int _max_cap;
// Producer/Consumer Subscript
int _p_step;
int _c_step;
// Space/Resource Semaphore
sem_t _space_sem;
sem_t _data_sem;
// Production/Consumption Lock
pthread_mutex_t _p_mtx;
pthread_mutex_t _c_mtx;
};