* @brief Lock-free double-ended queue.
* This file is a GNU parallel extension to the Standard C++ Library.
*/
#ifndef _GLIBCXX_PARALLEL_QUEUE_H
#define _GLIBCXX_PARALLEL_QUEUE_H 1
#include <parallel/types.h>
#include <parallel/base.h>
#include <parallel/compatibility.h>
#define _GLIBCXX_VOLATILE volatile
namespace __gnu_parallel
{
* atomic access. push_front() and pop_front() must not be called
* concurrently to each other, while pop_back() can be called
* concurrently at all times.
* @c empty(), @c size(), and @c top() are intentionally not provided.
* Calling them would not make sense in a concurrent setting.
* @param T Contained element type. */
template<typename T>
class RestrictedBoundedConcurrentQueue
{
private:
T* base;
sequence_index_t max_size;
atomically changeable value. */
_GLIBCXX_VOLATILE lcas_t borders;
public:
* @param max_size Maximal number of elements to be contained. */
RestrictedBoundedConcurrentQueue(sequence_index_t max_size)
{
this->max_size = max_size;
base = new T[max_size];
borders = encode2(0, 0);
#pragma omp flush
}
~RestrictedBoundedConcurrentQueue()
{ delete[] base; }
* Must not be called concurrently with pop_front(). */
void
push_front(const T& t)
{
lcas_t former_borders = borders;
int former_front, former_back;
decode2(former_borders, former_front, former_back);
*(base + former_front % max_size) = t;
#if _GLIBCXX_ASSERTIONS
_GLIBCXX_PARALLEL_ASSERT(((former_front + 1) - former_back)
<= max_size);
#endif
fetch_and_add(&borders, encode2(1, 0));
}
* Must not be called concurrently with pop_front(). */
bool
pop_front(T& t)
{
int former_front, former_back;
#pragma omp flush
decode2(borders, former_front, former_back);
while (former_front > former_back)
{
lcas_t former_borders = encode2(former_front, former_back);
lcas_t new_borders = encode2(former_front - 1, former_back);
if (compare_and_swap(&borders, former_borders, new_borders))
{
t = *(base + (former_front - 1) % max_size);
return true;
}
#pragma omp flush
decode2(borders, former_front, former_back);
}
return false;
}
* Must not be called concurrently with pop_front(). */
bool
pop_back(T& t)
{
int former_front, former_back;
#pragma omp flush
decode2(borders, former_front, former_back);
while (former_front > former_back)
{
lcas_t former_borders = encode2(former_front, former_back);
lcas_t new_borders = encode2(former_front, former_back + 1);
if (compare_and_swap(&borders, former_borders, new_borders))
{
t = *(base + former_back % max_size);
return true;
}
#pragma omp flush
decode2(borders, former_front, former_back);
}
return false;
}
};
}
#undef _GLIBCXX_VOLATILE
#endif