Как избежать дублирования кода с почти одинаковыми функциями-членами? - PullRequest
0 голосов
/ 30 октября 2019

Я реализовал очередь Майкла и Скотта (параллельную очередь без блокировки), и у меня возникла проблема с дублированием кода операции ожидания. В общем, этот вопрос не о самом алгоритме очереди, а о том, как правильно реализовать несколько вариантов функций, которые в основном имеют идентичную структуру. Пример, который я говорю:

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>>> часть.

1 Ответ

1 голос
/ 30 октября 2019

Если я правильно понимаю, вы можете создать универсальный метод с аргументом - функтор

template <class Func>
bool dequeue_generic(Func func) {

....

func(next_ptr->data)

}

, а затем реализовать методы с использованием различных функторов для работы с данными.

...