Я реализовал очередь Майкла и Скотта (параллельную очередь без блокировки), и у меня возникла проблема с дублированием кода операции ожидания. В общем, этот вопрос не о самом алгоритме очереди, а о том, как правильно реализовать несколько вариантов функций, которые в основном имеют идентичную структуру. Пример, который я говорю:
bool dequeue() {
while(true) {
// [atomically load head, tail and head->next]
auto head = m_head.load(std::memory_order_acquire);
auto head_ptr = head.get();
auto tail = m_tail.load(std::memory_order_acquire);
auto next = head_ptr->next.load(std::memory_order_acquire);
auto next_ptr = next.get();
// Are head, tail, and next consistent?
if(head == m_head.load(std::memory_order_acquire)) {
// Is queue empty or tail falling behind?
if(head_ptr == tail.get()) {
// Is queue empty?
if(!next_ptr) {
return false;
}
// tail is falling behind. Try to advance it
m_tail.compare_exchange_strong(tail, tail(next_ptr));
} else if(next_ptr){
// [ above check is result free list interaction, not part of orginal algo ]
// [Read value from next_ptr->data]
// <<<variant of operation here>>>>
}
}
}
}
Я планировал реализовать различные операции вместо <<<variant of operation here>>>>
, включая логику, код if-else, выходящий из цикла, и тому подобное, и я хотел бы избежать дублирования основной частифункция. Как мне поступить? Я использую по крайней мере C ++ 14 стандарта. Фоновая история состоит в том, что boost :: lockfree :: queue <> была слишком ограничена, и я хотел бы реализовать такие операции, как pop_if()
, compare_front()
, begin()
, которые все используют одну и ту же базовую логику кода операции удаления, за исключением<<<variant operation here>>>
часть.