8

I'm implementing a pointer / weak pointer mechanism using std::atomics for the reference counter (like this). For converting a weak pointer to a strong one I need to atomically

  • check if the strong reference counter is nonzero
  • if so, increment it
  • know whether something has changed.

Is there a way to do this using std::atomic_int? I think it has to be possible using one of the compare_exchange, but I can't figure it out.

Community
  • 1
  • 1
lucas clemente
  • 6,255
  • 8
  • 41
  • 61

2 Answers2

3

Given the definition std::atomic<int> ref_count;

int previous = ref_count.load();
for (;;)
{
    if (previous == 0)
        break;
    if (ref_count.compare_exchange_weak(previous, previous + 1))
        break;
}

previous will hold the previous value. Note that compare_exchange_weak will update previous if it fails.

ymett
  • 2,425
  • 14
  • 22
  • shouldnt ref_count.load() be in the for loop? I might be wrong, since I have really hard time thinking in atomic ops way. :) – NoSenseEtAl Dec 20 '12 at 10:46
  • 2
    @NoSenseEtAl `compare_exchange_weak` takes `previous` by reference and updates it, so there's no need to do another `ref_count.load()`. – ymett Dec 20 '12 at 11:54
1

This should do it:

bool increment_if_non_zero(std::atomic<int>& i) {
    int expected = i.load();
    int to_be_loaded = expected;

    do {
        if(expected == 0) {
            to_be_loaded = expected;
        }
        else {
            to_be_loaded = expected + 1;
        }
    } while(!i.compare_exchange_weak(expected, to_be_loaded));

    return expected;
}
Stephan Dollberg
  • 32,985
  • 16
  • 81
  • 107
  • It seems unnecessary to go ahead with the compare_exchange if you've already decided not to change the value. – ymett Dec 19 '12 at 11:14
  • @ymett I agree with you but I am somehow unsure, as I would else base my decision on whether to increment or not on two different states of `i`. – Stephan Dollberg Dec 19 '12 at 11:25
  • You only need to decide once. Once you've made the decision (in the `if`) you're finished. – ymett Dec 19 '12 at 11:27