Подтвердить что ты не робот

С++ 11 атомизация и интрузивный общий счет указателя ссылок

Я пишу интрузивный общий указатель, и я использую средства С++ 11 <atomic> для счетчика ссылок. Вот соответствующие фрагменты моего кода:

//...
mutable std::atomic<unsigned> count;
//...

void
SharedObject::addReference() const
{
    std::atomic_fetch_add_explicit (&count, 1u,
        std::memory_order_consume);
}

void
SharedObject::removeReference() const
{
    bool destroy;

    destroy = std::atomic_fetch_sub_explicit (&count, 1u,
        std::memory_order_consume) == 1;

    if (destroy)
        delete this;
}

Сначала я начал с memory_order_acquire и memory_order_release, но потом убедился, что memory_order_consume должен быть достаточно хорошим. После дальнейшего обсуждения мне кажется, что даже memory_order_relaxed должен работать.

Теперь вопрос заключается в том, могу ли я использовать memory_order_consume для операций или использовать более слабый порядок (memory_order_relaxed) или использовать более строгий порядок?

4b9b3361

Ответ 1

void
SharedObject::addReference() const
{
    std::atomic_fetch_add_explicit (&count, 1u, std::memory_order_relaxed);
}

void
SharedObject::removeReference() const
{
    if ( std::atomic_fetch_sub_explicit (&count, 1u, std::memory_order_release) == 1 ) {
         std::atomic_thread_fence(boost::memory_order_acquire);
         delete this;
    }
}

Вы хотите использовать atomic_thread_fence, чтобы delete был строго после fetch_sub. Reference

Цитата из связанного текста:

Увеличение счетчика ссылок всегда можно выполнить с помощью memory_order_relaxed: новые ссылки на объект могут быть сформированы из существующей ссылки и передачи существующей ссылки из одного нить в другую уже должна обеспечивать любую необходимую синхронизацию.

Важно обеспечить любой возможный доступ к объекту в одном нить (через существующую ссылку), чтобы произойти до удаления объект в другом потоке. Это достигается путем "выпуска" после сброса ссылки (любой доступ к объекту через эта ссылка, очевидно, должна была произойти раньше), и "приобретать", перед удалением объекта.

Можно было бы использовать memory_order_acq_rel для fetch_sub но это приводит к ненужным операциям "приобретать", когда контрольный счетчик еще не достиг нулевого уровня и может налагать производительность штраф.