Я думал о возвращаемых значениях этих двух функций. Возвращаемое значение функции __sync_bool_compare_and_swap, по-видимому, имеет очевидные преимущества, то есть я могу использовать его для определения того, имела ли место операция свопинга. Однако я не вижу хорошего использования возвращаемого значения __sync_val_compare_and_swap.__sync_val_compare_and_swap vs __sync_bool_compare_and_swap
Во-первых, позволяет иметь функцию подписи для справки (от GCC документы минус вар арг):
type __sync_val_compare_and_swap (type *ptr, type oldval type newval);
Проблема, которую я вижу, что возвращаемое значение __sync_val_compare_and_swap является старое значение * PTR. Точнее, это значение, которое было замечено в реализации этой функции после того, как были установлены соответствующие барьеры памяти. Я прямо заявляю это, чтобы удовлетворить тот факт, что между вызовом __sync_val_compare_and_swap и выполнением инструкций для обеспечения соблюдения барьера памяти значение * ptr может легко измениться.
Теперь, когда функция возвращает то, что я могу сделать с этим возвращаемым значением? Нет смысла пытаться сравнить его с * ptr, потому что теперь можно изменить ptr на других потоках. Точно так же сравнение newval и * ptr действительно не помогает мне (если я не блокирую * ptr, что, вероятно, подрывает мое использование атоматики в первую очередь).
Так что все, что мне осталось сделать, это спросить, действительно ли возвращается значение == oldval, которое эффективно (см. Ниже для оговорки), спрашивая, имела место операция свопинга. Поэтому я мог бы просто использовать __sync_bool_compare_and_swap.
Предостережение, о котором я только что упомянул, состоит в том, что единственное, что я вижу здесь, это то, что это не говорит мне, произошел ли обмен или нет, он просто говорит мне, что в какой-то момент до того, ptr имеет то же значение, что и newval. Я рассматриваю возможность, что oldval == newval (хотя я бы изо всех сил пытался эффективно реализовать функцию, чтобы сначала проверить эти значения и не менять их, если они были одинаковыми, так что это, вероятно, спорный вопрос). Однако я не вижу ситуации, когда знание этой разницы повлияло бы на меня на сайте вызова. На самом деле, я не могу представить ситуацию, когда я ставил бы oldval и newval равными.
Мой вопрос таким образом:
Стоит ли случай, в котором с помощью __sync_val_compare_and_swap и __sync_bool_compare_and_swap не будут эквивалентны, т.е. существует ситуация, когда один дает больше информации, чем другой?
ASIDE
Причина, я думал об этом было то, что я нашел реализацию __sync_val_compare_and_swap с точки зрения sync_bool_compare_and_swap, который имеет гонку:
inline int32_t __sync_val_compare_and_swap(volatile int32_t* ptr, int32_t oldval, int32_t newval)
{
int32_t ret = *ptr;
(void)__sync_bool_compare_and_swap(ptr, oldval, newval);
return ret;
}
Гонка быть на хранение * ptr в ret, поскольку * ptr может измениться до вызова __sync_bool_compare_and_swap. Это заставило меня понять, что я, похоже, не безопасен (без дополнительных барьеров или блокировок) реализации __sync_val_compare_and_swap с точки зрения sync_bool_compare_and_swap. Это заставило меня думать, что первый должен предоставить больше «информации», чем последний, но по моему вопросу я не вижу, что это действительно так.
Одно использование: возвращаемое текущее значение может использоваться для повтора. Я знаю, что есть атомарные приращения, но для иллюстрации предположим, что вы хотите реализовать это. Вы можете просто вызвать val_compare_and_swap со значением oldvalue как pre-increment и newvalue как pos-increment. Если вам это удастся, вы закончите. Если нет, повторите попытку, увеличив возвращаемое значение и снова вызовите val_compare_and_swap. С версией bool вам нужно будет сделать дополнительное чтение текущего значения для повтора. – kaylum
Вы правы, что код в вашем «в сторону» является ошибкой/имеет серьезное состояние гонки. Для правильной работы требуется петля повтора. См. Мой ответ. –