Я изучал реализацию атомарного подсчета ссылок.
Большинство операций очень согласованы между библиотеками, но я обнаружил удивительное разнообразие в операции «уменьшить счет». (Обратите внимание, что, как правило, единственная разница между общим и слабым decf в том, что называется on_zero()
. Исключения отмечены ниже.)
Если есть другие реализации, реализованные в терминах модели C11 / C ++ 11 (что делает MSVC?), Кроме типа «мы используем seq_cst, потому что мы не знаем ничего лучшего», не стесняйтесь редактировать их в.
Большинство примеров изначально были C ++, но здесь я переписал их на C, вставил и нормализовал в соответствии с соглашением >= 1
:
#include <stdatomic.h>
#include <stddef.h>
typedef struct RefPtr RefPtr;
struct RefPtr {
_Atomic(size_t) refcount;
};
// calls the destructor and/or calls free
// on a shared_ptr, this also calls decref on the implicit weak_ptr
void on_zero(RefPtr *);
Из Увеличение примеров intrusive_ptr и openssl :
void decref_boost_intrusive_docs(RefPtr *p) {
if (atomic_fetch_sub_explicit(&p->refcount, 1, memory_order_release) == 1) {
atomic_thread_fence(memory_order_acquire);
on_zero(p);
}
}
Можно было бы использовать memory_order_acq_rel для операции fetch_sub, но это приводит к ненужным операциям «получения», когда счетчик ссылок еще не достигает нуля и может налагать снижение производительности.
но большинство других (
1024 * Повышение *,
libstdc ++ ,
libc ++ shared
) сделать что-то еще:
void decref_common(RefPtr *p) {
if (atomic_fetch_sub_explicit(&p->refcount, 1, memory_order_acq_rel) == 1)
on_zero(p);
}
Но libc ++ делает что-то другое для слабого счетчика . Любопытно, что это во внешнем исходном файле:
void decref_libcxx_weak(RefPtr *p) {
if (atomic_load_explicit(&p->refcount, memory_order_acquire) == 1)
on_zero(p);
else
decref_common(p);
}
Тогда возникает вопрос: каковы реальные различия?
Подвопросы: комментарии неправильные? Что делают конкретные платформы (на aarch64 будет ldar
дешевле, чем dmb ishld
? Также ia64?)? При каких условиях можно использовать более слабые версии (например, если dtor - nop, если удалитель просто free
, ...)?
См. Также Подсчет атомных ссылок и Почему необходим барьер захвата перед удалением данных в интеллектуальном указателе с атомным подсчетом ссылок?