bbvan
bbvan

Reputation: 658

How to use gcc atomic builtins?

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

Answers (2)

I assume is_valid(A, B) can change depending on A.

In which case, this is not safe - consider the following sequence:

  • Thread 1 calls is_valid(A, B) and gets true
  • Thread 2 calls is_valid(A, B) and gets true
  • Thread 1 calls __sync_sub_and_fetch(A, B) changes A, and the new value of A means is_valid(A, B) is now false.
  • Thread 2 calls __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

Erix
Erix

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

Related Questions