Есть ли атомный прирост с предварительными условиями проверки, чтобы атомное значение было меньше указанного значения?
В новой стандартной операции атомарного приращения 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