简体   繁体   中英

Is comparing 2 int's an atomic operation?

I'm writing a very simple atomic counter, like

class counter
{
    /* ... */

    int increment()
    {
        return __sync_add_and_fetch( &counter_, 1 );
    }
    int decrement()
    {
        return __sync_sub_and_fetch( &counter_, 1 );
    }
    bool operator==( int val ) // const
    {
        return __sync_bool_compare_and_swap( &counter_, val, counter_ );
    }

private:
    volatile int counter_;
};

Can I use return counter_ == val; inside my operator== (shorter and will be able to uncomment the const qualifier)? Or I should use __sync_bool_compare_and_swap instead?


Edit: So, I'm more confused than in the beginning. After reading the comments and answers, I think leaving the "compare-and-swap" is more adequate. Is it?

Edit 2: I get rid of this operator== , but I'm still curious. I'll wait and hope for a bit more activity on this question. Thanks.

Yes and no.

Testing equality is atomic, insomuch as it is thread safe, but it only checks equality at that point in time. A fraction of a second one way or the other and the value you're comparing might have a different value. In particular, this is not a constant function because it uses hidden data that might change.

That said, I would use == here because your swap looks pointless.


Edit:

The point is that it's the variable load that needs to be atomic, not any of the other stuff.

Here's what your routine does:

  1. Receives some values in registers.

  2. Loads an integer from memory.

  3. Edits some values in registers.

  4. Returns.

There's only one thing there that has any bearing on concurrency: the load. The value of the counter may be changing continuously, but your routine cannot do anything special about that. Even with locking, the best it can do is load the current value and work with what it has.

It might be that the value has changed by the time the function returns, but all the code could ever hope to do is say whether it matched the value at the point it looked. It would be the responsibility of the caller to make sure that that's a valid thing to do (ie that nothing would update the counter until it was done).

A load of a struct, or an array, vector, or any other multi-value type would require that you acquire a read-lock to ensure that what you get is self-consistent (that the first bit you read corresponds to the last bit you read). But a load of an integer is pretty certain to be atomic (though not actually guaranteed by C/C++) so you need not worry.

The equality operator, == , operates only on the contents of your function's own context (registers and stack), and so there are no concurrency problems (unless you took an address of your stack variable and sent it to another thread).

Comparing 2 volatile variables is never mutexless atomic (I think you mean this), because you have to load the variables everytime from memory and cannot handle them in registers. The comparison is on most architectures done by substracting both and checking the zero value. This are at least 3 instructions.

The question for atomicity is only needed here, if there are decisions to make, because of any relation between two values. Because of the volatility of the values, you have to poll these values. Then atomicity of the comparison makes no sense, because if you won't succeed the equality in this turn you will get it in the next turn, but there is no gurantee that you will hit every equality. So in this sense, you comparison with __sync_bool_compare_and_swap makes no sense.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM