I have an atomic counter ( std::atomic<uint32_t> count ) that handles sequentially increasing values ββfor multiple threads.
uint32_t my_val = ++count;
Before I get my_val , I want to make sure that the increment will not overflow (i.e.: return to 0)
if (count == std::numeric_limits<uint32_t>::max()) throw std::runtime_error("count overflow");
I think this is a naive check, because if the check is performed by two threads before incrementing the counter, the second thread to increment will get 0 back
if (count == std::numeric_limits<uint32_t>::max()) // if 2 threads execute this throw std::runtime_error("count overflow"); uint32_t my_val = ++count; // before either gets here - possible overflow
I suppose I need to use the CAS operation to make sure that when I increment the counter, I really prevent a possible overflow.
So my questions are:
- Is my implementation correct?
- How effective is it (in particular, I need to double-check
max )?
My code (with a working example) follows:
#include <iostream> #include <atomic> #include <limits> #include <stdexcept> #include <thread> std::atomic<uint16_t> count; uint16_t get_val() // called by multiple threads { uint16_t my_val; do { my_val = count; // make sure I get the next value if (count.compare_exchange_strong(my_val, my_val + 1)) { // if I got the next value, make sure we don't overflow if (my_val == std::numeric_limits<uint16_t>::max()) { count = std::numeric_limits<uint16_t>::max() - 1; throw std::runtime_error("count overflow"); } break; } // if I didn't then check if there are still numbers available if (my_val == std::numeric_limits<uint16_t>::max()) { count = std::numeric_limits<uint16_t>::max() - 1; throw std::runtime_error("count overflow"); } // there are still numbers available, so try again } while (1); return my_val + 1; } void run() try { while (1) { if (get_val() == 0) exit(1); } } catch(const std::runtime_error& e) { // overflow } int main() { while (1) { count = 1; std::thread a(run); std::thread b(run); std::thread c(run); std::thread d(run); a.join(); b.join(); c.join(); d.join(); std::cout << "."; } return 0; }
c ++ atomic c ++ 11
Steve lorimer
source share