Reputation: 658
In my program I was trying to update a value from multiple threads. I know how to use mutex (pthread_mutex_lock(), pthread_mutex_unlock()
) to do this, but I just learned about gcc atomic builtins so I would like to have a try.
shared value A;
void each_working_thread() {
thread local variable B;
if (is_valid(A,B))
__sync_sub_and_fetch(A,B);
else
throw error;
}
where is_valid()
is a const function that return boolean.
Is this correct, or the value of A could be updated by another thread during is_valid()
?
Upvotes: 1
Views: 1842
Reputation: 58868
I assume is_valid(A, B) can change depending on A.
In which case, this is not safe - consider the following sequence:
is_valid(A, B)
and gets trueis_valid(A, B)
and gets true__sync_sub_and_fetch(A, B)
changes A, and the new value of A means is_valid(A, B)
is now false.__sync_sub_and_fetch(A, B)
even though it shouldn't because is_valid(A, B)
is now false.You may be interested in the compare-exchange operation. In this case you can write something like:
int oldValueOfA, newValueOfA;
do {
oldValueOfA = A;
__sync_synchronize(); // memory barrier; makes sure A doesn't get accessed after this line
if (!is_valid(oldValueOfA, B))
throw error;
newValueOfA = oldValueOfA - B;
} while(!__sync_bool_compare_and_swap(&A, oldValueOfA, newValueOfA));
You can't make the two operations atomic, but you can detect if they weren't atomic and then you can try again.
This works because if A
doesn't still contain oldValueOfA
, __sync_bool_compare_and_swap
does nothing and returns false. Otherwise, it sets it to newValueOfA
and returns true. So if it returns true, you know nobody else changed A
while you were busy calling is_valid
. And if it returns false, then you haven't actually done anything yet, so you're free to go back and try again.
Note that is_valid
might be called several times; this is relevant if it has side effects (like printing a message on the screen). In that case you should just use a mutex.
Upvotes: 1
Reputation: 7105
That probably is not thread safe, depending on what exactly is_valid does.
The point of that specific builtin is just to perform an atomic subtraction.
Consider this code
A = A - B;
This is not thread safe because it requires at least 2 atomic steps - the A - B, and then the assignment back to A. The builtin for this solves that one scenario.
Upvotes: 0