Есть ли атомный прирост с предварительными условиями проверки, чтобы атомное значение было меньше указанного значения?

В новой стандартной операции атомарного приращения C ++ с предварительными условиями проверки перед увеличенным значением атомное значение было меньше указанного значения?

Могу ли я сделать это проще и быстрее, чем следующий код?

int atomic_inc(std::atomic_int& val, int less_than) {
int new_val;
int old_val = val.load();
do
{
if (old_val > less_than) return old_val;
new_val = old_val + 1;
} while (!val.compare_exchange_weak(old_val, new_val));

return new_val;
}

Если кто-то не знает, как это работает, сравните_exchange_weak:
compare_exchange_weak читает val, сравнивает со old_val и, если они не равны, сохраняет val в old_val. Если оно равно, сохраните new_val в val.

2

Решение

Нет, нет особой поддержки для увеличения значений меньше значения. Ваш код настолько эффективен, насколько вы можете получить. В C ++ 11 нет варианта без ожидания

Существует неограниченное количество возможных шаблонов «увеличения, если X». Производители оборудования решили, что единственное, что им нужно поддерживать — это «увеличение, если не изменение».

Теоретически вы могли бы изобрести аппаратную платформу со специальным ассемблерным кодом для нее, но C ++ 11 прямо не нацелен на это.

1

Другие решения

То, что я делал в прошлом, может сработать для вас, в зависимости от того, для чего вы это используете.

Если вы можете предположить, что val не будете часто обрезать — так что возможная оптимизация отказа от использования CAS не сильно вас спасет — вы можете просто слепо увеличивать значение и корректировать его после прочтения:

int atomic_inc(std::atomic_int& val, int less_than) {
return std::min(++val, less_than);
}

А потом изредка клип val вернуться к less_than при необходимости, достаточно часто, чтобы вам не пришлось беспокоиться о int переполнен, и ты золотой.

1

Если вы используете потоки, вы можете использовать mutex для атомарного приращения. Вот как вы это сделаете в этом случае:

Объявите и инициализируйте мьютекс глобально:

pthread_mutex_t lock;
pthread_mutex_init(&lock, NULL)

В одной теме:

int atomic_inc(std::atomic_int& val, int less_than) {
pthread_mutex_lock(&lock);
int newVal = val.load();
if (newVal < less_than)
newVal++
pthread_mutex_unlock(&lock);
return new_val;
}

Вам придется заблокировать и разблокировать мьютекс перед изменением val в любой другой теме.

Для получения дополнительной информации о мьютексе: http://www.yolinux.com/TUTORIALS/LinuxTutorialPosixThreads.html#SYNCHRONIZATION

-3