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:
Receives some values in registers.
Loads an integer from memory.
Edits some values in registers.
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 (i.e. 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).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With