queue.h
Go to the documentation of this file.
// -*- C++ -*-
// Copyright (C) 2007-2021 Free Software Foundation, Inc.
//
// This file is part of the GNU ISO C++ Library. This library is free
// software; you can redistribute it and/or modify it under the terms
// of the GNU General Public License as published by the Free Software
// Foundation; either version 3, or (at your option) any later
// version.
// This library is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
// Under Section 7 of GPL version 3, you are granted additional
// permissions described in the GCC Runtime Library Exception, version
// 3.1, as published by the Free Software Foundation.
// You should have received a copy of the GNU General Public License and
// a copy of the GCC Runtime Library Exception along with this program;
// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
// <http://www.gnu.org/licenses/>.
/** @file parallel/queue.h
* @brief Lock-free double-ended queue.
* This file is a GNU parallel extension to the Standard C++ Library.
*/
// Written by Johannes Singler.
#ifndef _GLIBCXX_PARALLEL_QUEUE_H
#define _GLIBCXX_PARALLEL_QUEUE_H 1
#include <parallel/types.h>
#include <parallel/base.h>
#include <parallel/compatibility.h>
/** @brief Decide whether to declare certain variable volatile in this file. */
#define _GLIBCXX_VOLATILE volatile
namespace __gnu_parallel
{
/**@brief Double-ended queue of bounded size, allowing lock-free
* 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 _Tp Contained element type. */
template<typename _Tp>
class _RestrictedBoundedConcurrentQueue
{
private:
/** @brief Array of elements, seen as cyclic buffer. */
_Tp* _M_base;
/** @brief Maximal number of elements contained at the same time. */
_SequenceIndex _M_max_size;
/** @brief Cyclic __begin and __end pointers contained in one
atomically changeable value. */
_GLIBCXX_VOLATILE _CASable _M_borders;
public:
/** @brief Constructor. Not to be called concurrent, of course.
* @param __max_size Maximal number of elements to be contained. */
_RestrictedBoundedConcurrentQueue(_SequenceIndex __max_size)
{
_M_max_size = __max_size;
_M_base = new _Tp[__max_size];
_M_borders = __encode2(0, 0);
#pragma omp flush
}
/** @brief Destructor. Not to be called concurrent, of course. */
~_RestrictedBoundedConcurrentQueue()
{ delete[] _M_base; }
/** @brief Pushes one element into the queue at the front end.
* Must not be called concurrently with pop_front(). */
void
push_front(const _Tp& __t)
{
_CASable __former_borders = _M_borders;
int __former_front, __former_back;
__decode2(__former_borders, __former_front, __former_back);
*(_M_base + __former_front % _M_max_size) = __t;
#if _GLIBCXX_PARALLEL_ASSERTIONS
// Otherwise: front - back > _M_max_size eventually.
_GLIBCXX_PARALLEL_ASSERT(((__former_front + 1) - __former_back)
<= _M_max_size);
#endif
__fetch_and_add(&_M_borders, __encode2(1, 0));
}
/** @brief Pops one element from the queue at the front end.
* Must not be called concurrently with pop_front(). */
bool
pop_front(_Tp& __t)
{
int __former_front, __former_back;
#pragma omp flush
__decode2(_M_borders, __former_front, __former_back);
while (__former_front > __former_back)
{
// Chance.
_CASable __former_borders = __encode2(__former_front,
__former_back);
_CASable __new_borders = __encode2(__former_front - 1,
__former_back);
if (__compare_and_swap(&_M_borders, __former_borders,
__new_borders))
{
__t = *(_M_base + (__former_front - 1) % _M_max_size);
return true;
}
#pragma omp flush
__decode2(_M_borders, __former_front, __former_back);
}
return false;
}
/** @brief Pops one element from the queue at the front end.
* Must not be called concurrently with pop_front(). */
bool
pop_back(_Tp& __t) //queue behavior
{
int __former_front, __former_back;
#pragma omp flush
__decode2(_M_borders, __former_front, __former_back);
while (__former_front > __former_back)
{
// Chance.
_CASable __former_borders = __encode2(__former_front,
__former_back);
_CASable __new_borders = __encode2(__former_front,
__former_back + 1);
if (__compare_and_swap(&_M_borders, __former_borders,
__new_borders))
{
__t = *(_M_base + __former_back % _M_max_size);
return true;
}
#pragma omp flush
__decode2(_M_borders, __former_front, __former_back);
}
return false;
}
};
} //namespace __gnu_parallel
#undef _GLIBCXX_VOLATILE
#endif /* _GLIBCXX_PARALLEL_QUEUE_H */
base.h
Sequential helper functions. This file is a GNU parallel extension to the Standard C++ Library.
_GLIBCXX_VOLATILE
#define _GLIBCXX_VOLATILE
Decide whether to declare certain variable volatile in this file.
Definition: queue.h:40
types.h
Basic types and typedefs. This file is a GNU parallel extension to the Standard C++ Library.
__gnu_parallel
GNU parallel code for public use.
Definition: balanced_quicksort.h:62
__gnu_parallel::_SequenceIndex
uint64_t _SequenceIndex
Unsigned integer to index __elements. The total number of elements for each algorithm must fit into t...
Definition: types.h:117
__gnu_parallel::__fetch_and_add
_Tp __fetch_and_add(volatile _Tp *__ptr, _Tp __addend)
Add a value to a variable, atomically.
Definition: parallel/compatibility.h:74
__gnu_parallel::__encode2
_CASable __encode2(int __a, int __b)
Encode two integers into one gnu_parallel::_CASable.
Definition: base.h:119
__gnu_parallel::_CASable
int64_t _CASable
Longest compare-and-swappable integer type on this platform.
Definition: types.h:127
__gnu_parallel::__compare_and_swap
bool __compare_and_swap(volatile _Tp *__ptr, _Tp __comparand, _Tp __replacement)
Compare-and-swap.
Definition: parallel/compatibility.h:108
__gnu_parallel::__decode2
void __decode2(_CASable __x, int &__a, int &__b)
Decode two integers from one gnu_parallel::_CASable.
Definition: base.h:133
__gnu_parallel::_RestrictedBoundedConcurrentQueue
Double-ended queue of bounded size, allowing lock-free atomic access. push_front() and pop_front() mu...
Definition: queue.h:53
__gnu_parallel::_RestrictedBoundedConcurrentQueue::~_RestrictedBoundedConcurrentQueue
~_RestrictedBoundedConcurrentQueue()
Destructor. Not to be called concurrent, of course.
Definition: queue.h:77
__gnu_parallel::_RestrictedBoundedConcurrentQueue::push_front
void push_front(const _Tp &__t)
Pushes one element into the queue at the front end. Must not be called concurrently with pop_front().
Definition: queue.h:83
__gnu_parallel::_RestrictedBoundedConcurrentQueue::pop_front
bool pop_front(_Tp &__t)
Pops one element from the queue at the front end. Must not be called concurrently with pop_front().
Definition: queue.h:100
__gnu_parallel::_RestrictedBoundedConcurrentQueue::_RestrictedBoundedConcurrentQueue
_RestrictedBoundedConcurrentQueue(_SequenceIndex __max_size)
Constructor. Not to be called concurrent, of course.
Definition: queue.h:68
__gnu_parallel::_RestrictedBoundedConcurrentQueue::pop_back
bool pop_back(_Tp &__t)
Pops one element from the queue at the front end. Must not be called concurrently with pop_front().
Definition: queue.h:127
compatibility.h
Compatibility layer, mostly concerned with atomic operations.