Какие-нибудь недостатки для std::atomic_flag, не обеспечивающего операции загрузки или хранения? (Пример Spin-Lock)

Сравнивая std::atomic_flag для std::atomic_bool (ака std::atomic<bool> мне кажется, что std::atomic_flag просто имеет более простой интерфейс. Он обеспечивает только тестирование + установку и очистку флага во время std::atomic_bool также обеспечивает перегрузки для нескольких операторов.

Один мой вопрос касается терминологии: что подразумевается под "операциями загрузки или хранения"? Означает ли это, что невозможно произвольно прочитать и изменить std::atomic_flag ценность?

Кроме того, мне интересно, std::atomic_bool Быть быстрее, когда используется для спин-блокировки? Мне кажется, что std::atomic_flag всегда должен читать и писать во время спин-блокировки:

while (my_atomic_flag.test_and_set()); // spin-lock

в то время как std::atomic_bool нужно будет только выполнить операцию чтения (при условии, что атомарный тип bool реализован без блокировки):

while (my_atomic_bool); // spin-lock

Является std::atomic_flag строго эффективнее, чем std::atomic_bool или это может быть наоборот? Что следует использовать для спин-блокировки?

1 ответ

Решение

Что подразумевается под "операциями загрузки или хранения"? Означает ли это, что невозможно произвольно прочитать и изменить значение std::atomic_flag?

Обычные операции сохранения / загрузки не поддерживаются std::atomic_flag,
Это тип только для модификации; то есть. вы не можете прочитать доступ std::atomic_flag объект без выполнения модифицирующей операции.
В общем, std::atomic_flag подразумевается как строительный блок для других операций. Его интерфейс преднамеренно прост; это единственный атомарный тип, который имеет гарантированные атомарные операции без блокировки. Поддерживаемые операции:

std::atomic_flag::clear()
std::atomic_flag::test_and_set()

При этом вы можете легко создать свой собственный спинлок (хотя обычно это не рекомендуется):

class my_spinlock {
    std::atomic_flag flag = ATOMIC_FLAG_INIT;
public:

    void lock()
    {
        while(flag.test_and_set());
    }

    void unlock()
    {
        flag.clear();
    }
};

Кроме того, мне интересно, может ли std::atomic_bool быть быстрее при использовании для спин-блокировки? Мне кажется, что std::atomic_flag всегда должен читать и писать во время спин-блокировки

Что ж, дело в том, что спин-блокировка всегда должна изменять свое состояние при получении блокировки. Вы просто не можете взломать замок, не сказав об этом другим.
Реализация для lock() основанный на std::atomic<bool> выглядит очень похоже:

while (flag.exchange(true)); 

Будь спинлок на основе std::atomic_flag быстрее?
На моей платформе компилятор выдает одинаковую сборку для обоих типов, поэтому я был бы очень удивлен.

Другие вопросы по тегам