forked from Alepha/Alepha
94 lines
1.6 KiB
C++
94 lines
1.6 KiB
C++
static_assert( __cplusplus > 2020'99 );
|
|
|
|
#pragma once
|
|
|
|
#include <Alepha/Alepha.h>
|
|
|
|
#include <cassert>
|
|
|
|
#include <queue>
|
|
|
|
#include <boost/circular_buffer.hpp>
|
|
|
|
#include <Alepha/Thread.h>
|
|
|
|
namespace Alepha::Hydrogen::Atomic ::detail:: DeadDrop_m
|
|
{
|
|
inline namespace exports
|
|
{
|
|
template< typename Item >
|
|
class DeadDrop;
|
|
}
|
|
|
|
template< typename Item >
|
|
class exports::DeadDrop
|
|
{
|
|
private:
|
|
Alepha::mutex access;
|
|
|
|
struct Box
|
|
{
|
|
private:
|
|
Alepha::mutex *access= nullptr;
|
|
Alepha::condition_variable ready;
|
|
|
|
Item original;
|
|
|
|
Item *active= &original;
|
|
boost::circular_buffer< Item * > next{ 2 };
|
|
|
|
Box *companion= nullptr;
|
|
|
|
friend DeadDrop;
|
|
|
|
void
|
|
setup( Alepha::mutex *const access, Box *const companion )
|
|
{
|
|
this->access= access;
|
|
this->companion= companion;
|
|
}
|
|
|
|
public:
|
|
Item &
|
|
acquireBox()
|
|
{
|
|
if( not active )
|
|
{
|
|
[[unlikely]];
|
|
std::unique_lock lock{ *access };
|
|
ready.wait( lock, [&]{ return not next.empty(); } );
|
|
active= next.front();
|
|
next.pop_front();
|
|
}
|
|
assert( active );
|
|
return *active;
|
|
}
|
|
|
|
void
|
|
releaseBox()
|
|
{
|
|
std::unique_lock lock{ *access };
|
|
companion->next.push_back( active );
|
|
active= nullptr;
|
|
companion->ready.notify_one();
|
|
}
|
|
};
|
|
|
|
public:
|
|
Box producer;
|
|
Box consumer;
|
|
|
|
explicit
|
|
DeadDrop()
|
|
{
|
|
producer.setup( &this->access, &consumer );
|
|
consumer.setup( &this->access, &producer );
|
|
}
|
|
};
|
|
}
|
|
|
|
namespace Alepha::Hydrogen::Atomic::inline exports::inline DeadDrop_m
|
|
{
|
|
using namespace detail::DeadDrop_m::exports;
|
|
}
|