Если это не ошибка в boost::lockfree::detail::freelist, что мне здесь не хватает?

В этом файле класс boost::lockfree::detail::freelist используется для управления хранилищем безблокировочной структуры данных (например, очереди) с использованием свободного списка. Метод deallocate_impl используется для освобождения узлов путем связывания их обратно со списком свободных узлов (освобожденный узел становится новым главой списка свободных, замещая старую главу). Этот метод должен быть потокобезопасным и не блокировать. Оригинальный исходный код одного экземпляра дублируется здесь с моими комментариями, аннотированными, чтобы указать на подозрительный код (потенциальную ошибку?):

void deallocate_impl (index_t index)
{
    freelist_node * new_pool_node =
           reinterpret_cast<freelist_node*>(NodeStorage::nodes() + index);

    // Shouldn't this line be placed inside the loop?
    // The loop continues as long as the compare-and-exchange fails,
    // which happens if the pool head has been concurrently updated.
    // In that case, we MUST reload the new value of "pool_" to
    // reuse its tag, link the new free-list head to it and
    // compare against in the compare_and_exchange call.
    tagged_index old_pool = pool_.load(memory_order_consume);

    for(;;) {
        // The old pool head tag is reused here without causing
        // any ABA problems. However, if "index" is the same as
        // old_pool.get_index(), a self-reference is written.
        tagged_index new_pool (index, old_pool.get_tag());
        new_pool_node->next.set_index(old_pool.get_index());

        if (pool_.compare_exchange_weak(old_pool, new_pool))
            return;
    }
}

Я видел такую ​​же реализацию и в Boost 1.62.0.


person Ahmed Nassar    schedule 20.03.2017    source источник
comment
Один из больших недостатков С++, не обозначающий передачу по ссылкам на вызывающем сайте. Сравните обменные обновления ожидаемого значения с видимым в данный момент.   -  person Voo    schedule 20.03.2017
comment
Спасибо, @Voo.   -  person Ahmed Nassar    schedule 20.03.2017


Ответы (1)


Цикл продолжается до тех пор, пока происходит сбой сравнения и обмена, что происходит, если головная часть пула была одновременно обновлена. В этом случае мы ДОЛЖНЫ перезагрузить новое значение «pool_», чтобы повторно использовать его тег...

compare_exchange_weak() записывает предыдущее значение pool_ в old_pool после каждого вызова. Документация для compare_exchange_weak()< /а>.

Однако, если "индекс" совпадает с old_pool.get_index()...

Вероятно, этого не может произойти, так как узел с таким индексом еще не был перемещен в свободный список.

person Grisha    schedule 20.03.2017
comment
Спасибо @Гриша. Я должен был посмотреть документацию, прежде чем публиковать вопрос. - person Ahmed Nassar; 20.03.2017