Инкремент std::atomic с контролем переполнения

249
19 ноября 2017, 16:41

Потребовалось реализовать потоково и переполнительно безопасный счетчик на std::atomic. Сделал вот так, как и многие в интернете:

template<typename T, T COUNT_MIN = std::numeric_limits<T>::min()
                   , T COUNT_MAX = std::numeric_limits<T>::max() >
T SafeIncrement(std::atomic<T> & counter)
{
   static_assert(MIN < MAX, "range wrong");
   T current = counter.load();
   T result  = current == COUNT_MAX  ? COUNT_MIN  : current + 1;
   while(!counter.compare_exchange_strong(current, result))
   {
       result = current == COUNT_MAX ? COUNT_MIN : current + 1;
   }
   return result;
}

Но у меня возникло подозрение, не возникнет ли здесь гонок. При интенсивном почти непрерывном вызове SafeIncrement из параллельных потоков, не возможна ли ситуация когда отдельные потоки будут вечно (или надолго!) промахиваться с обменом пусть и атомарном?

Поясню о чем речь. Гонка была бы невозможна если бы потоки выполняли обмен строго экслюзивно и по-очередеи. Например, если они исполняются псевдопараллельно на одном вычислителе или такой механиз обеспечивает ОС. У нас же гарантируется только экслюзивность, а не очередность.

Так вот, на эту тему что-то предусмотрено в реализациях std::atomic? Или есть правильные решения?

Answer 1

Нет, такая ситуация невозможна. Потому что каждая ошибка обмена означает что какой-то другой поток успешно этот самый обмен совершил. Таким образом, на каждой итерации цикла уменьшается число конкурирующих потоков - а значит, рано или поздно они закончатся (если только по какой-то причине не прибывают быстрее чем убывают).

Однако, значительное замедление при одновременном доступе из разных потоков действительно возможно, поэтому таких переменных стоит избегать.

PS Ваше решение мне кажется каким-то переусложненным: можно же просто использовать беззнаковые целочисленные типы, у них переполнение не вызывает UB.

READ ALSO
Добавление элемента в модель

Добавление элемента в модель

Не могу понять как происходит взаимодействие модели и представленияНужно добавить элемент в модель и установить для него виджет в отображении

198
Неправильная конвертация lat/long в UTM

Неправильная конвертация lat/long в UTM

Имею вот такие координаты в latitude и longitude

242
Битмап из ресурсов и кисть

Битмап из ресурсов и кисть

Хочу закрасить окно узором битмапа, который грузится из ресурсов и помещается в кистьНе могу понять какие лучше функции использовать и с чего...

219
Оптимизация tmp переменной в функции

Оптимизация tmp переменной в функции

Подскажите, пожалуйста, какую оптимизацию проведет компилятор в таком коде:

247