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

В новой стандартной операции атомарного приращения 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;
}

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

3 ответа

Решение

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

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

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

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

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

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

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

Если вы используете потоки, вы можете использовать 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

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