Skip to content

Instantly share code, notes, and snippets.

@madmongo1
Created June 1, 2021 10:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save madmongo1/cb4d9770d458f9860dde438aca5068b4 to your computer and use it in GitHub Desktop.
Save madmongo1/cb4d9770d458f9860dde438aca5068b4 to your computer and use it in GitHub Desktop.
Atomic transfer between polymorphic producer and consumer
/// @brief The result of attemping an atomic produce, consume or produce and
/// consume.
struct io_transfer_result
{
/// 1 if the transfer completed
unsigned char success : 1 = 0;
/// 1 if the consumer is in the completed state
unsigned char consumed : 1 = 0;
/// 1 if the prodicer is in the completed state
unsigned char produced : 1 = 0;
};
// clang-format off
/// @brief Attempt to transfer the contents of the producer to the consumer
///
/// The function will keep attempting delivery until either delivery occurs or
/// one or other of the producer and consumer enters the committed state.
/// The transfer, it occurs will be atomic - i.e. the producer will not give up
/// its value if the consumer is not in a state to accept it.
/// The return value is a an @see io_transfer_result indicating the final state
/// of the producer and consumer and whether the value was transferred.
/// Only the following return value combinations are possible:
///
/// success | consumed | produced | Description
/// ------- | -------- | -------- | -----------
/// 1 | 1 | 1 | The transfer occurred. Both producer and consumer can be safely discarded.
/// 0 | 1 | 1 | The transfer did not occur. Both producer and consumer should be discarded.
/// 0 | 0 | 1 | The transfer did not occur. The producer should be discarded. The consumer is still awaiting a value.
/// 0 | 1 | 0 | The transfer did not occur. The consumer should be discarded. The producer still holds a value.
///
/// @tparam ValueType Is the type of value being transferred
/// @param producer is a reference to the producer object
/// @param consumer is a reference to the consumer object
/// @return The result of the atomic transfer
// clang-format on
template < class ValueType >
io_transfer_result
transfer_producer_to_consumer(produce_op_interface< ValueType > &producer,
consume_op_interface< ValueType > &consumer)
{
again:
auto result = io_transfer_result();
switch (consumer.reserve())
{
case io_op_action_code::action_completed:
result.consumed = true;
goto done;
case io_op_action_code::action_busy:
BOOST_CHANNELS_BUSY_WAIT();
goto again;
case io_op_action_code::action_reserved:
switch (producer.reserve())
{
case io_op_action_code::action_completed:
consumer.release();
result.produced = 1;
goto done;
case io_op_action_code::action_busy:
consumer.release();
BOOST_CHANNELS_BUSY_WAIT();
goto again;
case io_op_action_code::action_reserved:
// success case
consumer.commit(producer.consume());
result.produced = 1;
result.consumed = 1;
result.success = 1;
break;
}
}
done:
return result;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment