Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.programming.threads > #7746
| Path | csiph.com!eternal-september.org!reader02.eternal-september.org!.POSTED!not-for-mail |
|---|---|
| From | Bonita Montero <Bonita.Montero@gmail.com> |
| Newsgroups | comp.programming.threads |
| Subject | A thread-queue |
| Date | Wed, 1 Jun 2022 20:42:36 +0200 |
| Organization | A noiseless patient Spider |
| Lines | 207 |
| Message-ID | <t78bug$laf$1@dont-email.me> (permalink) |
| MIME-Version | 1.0 |
| Content-Type | text/plain; charset=UTF-8; format=flowed |
| Content-Transfer-Encoding | 7bit |
| Injection-Date | Wed, 1 Jun 2022 18:42:24 -0000 (UTC) |
| Injection-Info | reader02.eternal-september.org; posting-host="bb8f0ac5e94ee4d40cf7ef27c23d2aeb"; logging-data="21839"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX1/zvdz2v1edzkqsZDwHBMuMeacDmezADSo=" |
| User-Agent | Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:91.0) Gecko/20100101 Thunderbird/91.10.0 |
| Cancel-Lock | sha1:esiMp4gSgcx1zvhtembo62Xl8KM= |
| Content-Language | de-DE |
| Xref | csiph.com comp.programming.threads:7746 |
Show key headers only | View raw
A thread-queue in C++20, with a flexibility (especially because of
the functional programming parts) that would never be possible with
FreePascal or Delphi; these languages simply suck.
#pragma once
#include <deque>
#include <mutex>
#include <condition_variable>
#include <utility>
#include <concepts>
#include <list>
template<typename QueueType>
concept thread_queue_concept =
std::same_as<QueueType, std::deque<typename QueueType::value_type,
typename QueueType::allocator_type>>
|| std::same_as<QueueType, std::list<typename QueueType::value_type,
typename QueueType::allocator_type>>;
template<typename QueueType>
requires thread_queue_concept<QueueType>
struct thread_queue
{
using value_type = typename QueueType::value_type;
thread_queue();
explicit thread_queue( typename QueueType::allocator_type const &alloc );
thread_queue( thread_queue &&other );
thread_queue &operator =( thread_queue const & ) = delete;
thread_queue &operator =( thread_queue &&other );
bool empty() const;
std::size_t size() const;
void shrink_to_fit();
void clear();
template<typename ... Args>
requires std::is_constructible_v<typename QueueType::value_type, Args ...>
void enque( Args &&... args );
template<typename Producer>
requires requires( Producer producer ) { { producer() } ->
std::same_as<std::pair<bool, typename QueueType::value_type>>; }
void enqueue_multiple( Producer producer );
template<typename Consumer>
requires requires( Consumer consumer, typename QueueType::value_type
value ) { { consumer( std::move( value ) ) } -> std::same_as<bool>; }
void dequeue_multiple( Consumer consumer );
typename QueueType::value_type dequeue();
QueueType container() noexcept;
void swap( thread_queue &other );
private:
mutable std::mutex m_mtx;
mutable std::condition_variable m_cv;
QueueType m_queue;
};
template<typename QueueType>
requires thread_queue_concept<QueueType>
thread_queue<QueueType>::thread_queue()
{
}
template<typename QueueType>
requires thread_queue_concept<QueueType>
thread_queue<QueueType>::thread_queue( typename
QueueType::allocator_type const &alloc ) :
m_queue( alloc )
{
}
template<typename QueueType>
requires thread_queue_concept<QueueType>
thread_queue<QueueType>::thread_queue( thread_queue &&other )
{
using namespace std;
lock_guard lock( other.m_mtx );
m_queue = move( other.m_queue );
}
template<typename QueueType>
requires thread_queue_concept<QueueType>
thread_queue<QueueType> &thread_queue<QueueType>::thread_queue::operator
=( thread_queue &&other )
{
using namespace std;
lock_guard
ourLock( m_mtx ),
otherLock( other.m_mtx );
m_queue = move( other.m_queue );
return *this;
}
template<typename QueueType>
requires thread_queue_concept<QueueType>
bool thread_queue<QueueType>::thread_queue::empty() const
{
std::lock_guard lock( m_mtx );
return m_queue.empty();
}
template<typename QueueType>
requires thread_queue_concept<QueueType>
std::size_t thread_queue<QueueType>::thread_queue::size() const
{
std::lock_guard lock( m_mtx );
return m_queue.size();
}
template<typename QueueType>
requires thread_queue_concept<QueueType>
void thread_queue<QueueType>::thread_queue::shrink_to_fit()
{
std::lock_guard lock( m_mtx );
return m_queue.shrink_to_fit();
}
template<typename QueueType>
requires thread_queue_concept<QueueType>
void thread_queue<QueueType>::thread_queue::clear()
{
std::lock_guard lock( m_mtx );
m_queue.clear();
}
template<typename QueueType>
requires thread_queue_concept<QueueType>
template<typename ... Args>
requires std::is_constructible_v<typename QueueType::value_type, Args ...>
void thread_queue<QueueType>::thread_queue::enque( Args &&... args )
{
using namespace std;
unique_lock lock( m_mtx );
m_queue.emplace_front( forward<Args>( args ) ... );
m_cv.notify_one();
}
template<typename QueueType>
requires thread_queue_concept<QueueType>
typename QueueType::value_type
thread_queue<QueueType>::thread_queue::dequeue()
{
using namespace std;
unique_lock lock( m_mtx );
while( m_queue.empty() )
m_cv.wait( lock );
value_type value = move( m_queue.back() );
m_queue.pop_back();
return value;
}
template<typename QueueType>
requires thread_queue_concept<QueueType>
template<typename Producer>
requires requires( Producer producer ) { { producer() } ->
std::same_as<std::pair<bool, typename QueueType::value_type>>; }
void thread_queue<QueueType>::enqueue_multiple( Producer producer )
{
using namespace std;
lock_guard lock( m_mtx );
for( std::pair<bool, value_type> ret; (ret = move( producer() )).first; )
m_queue.emplace_front( move( ret.second ) ),
m_cv.notify_one();
}
template<typename QueueType>
requires thread_queue_concept<QueueType>
template<typename Consumer>
requires requires( Consumer consumer, typename QueueType::value_type
value ) { { consumer( std::move( value ) ) } -> std::same_as<bool>; }
void thread_queue<QueueType>::dequeue_multiple( Consumer consumer )
{
using namespace std;
unique_lock lock( m_mtx );
for( ; ; )
{
while( m_queue.empty() )
m_cv.wait( lock );
try
{
bool cont = consumer( move( m_queue.back() ) );
m_queue.pop_back();
if( !cont )
return;
}
catch( ... )
{
m_queue.pop_back();
throw;
}
}
}
template<typename QueueType>
requires thread_queue_concept<QueueType>
QueueType thread_queue<QueueType>::container() noexcept
{
using namespace std;
unique_lock lock( m_mtx );
return move( m_queue );
}
template<typename QueueType>
requires thread_queue_concept<QueueType>
void thread_queue<QueueType>::thread_queue::swap( thread_queue &other )
{
std::lock_guard
ourLock( m_mtx ),
otherLock( other.m_mtx );
m_queue.swap( other.m_queue );
}
Back to comp.programming.threads | Previous | Next | Find similar | Unroll thread
A thread-queue Bonita Montero <Bonita.Montero@gmail.com> - 2022-06-01 20:42 +0200
csiph-web