如何使用gcc atomic builtins?

时间:2016-12-07 02:22:11

标签: c++ multithreading gcc

在我的程序中,我试图从多个线程更新一个值。我知道如何使用互斥(pthread_mutex_lock(), pthread_mutex_unlock())来做到这一点,但我刚刚学习了gcc原子内置,所以我想尝试一下。

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;
}

其中is_valid()是一个返回布尔值的const函数。

这是正确的,还是在is_valid()期间另一个线程可以更新A的值?

2 个答案:

答案 0 :(得分:1)

我假设is_valid(A,B)可以根据A而改变。

在这种情况下,这是不安全的 - 请考虑以下顺序:

  • 主题1调用is_valid(A, B)并获得真实
  • 线程2调用is_valid(A, B)并获得真实
  • 主题1调用__sync_sub_and_fetch(A, B)更改A,而新值A意味着is_valid(A, B)现在为假。
  • 线程2调用__sync_sub_and_fetch(A, B),即使它不应该因为is_valid(A, B)现在为假。

您可能对 compare-exchange 操作感兴趣。在这种情况下,您可以编写如下内容:

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));

你不能使这两个操作成为原子,但你可以检测,如果它们不是原子然后你可以再试一次。

这是有效的,因为如果A仍未包含oldValueOfA,则__sync_bool_compare_and_swap不执行任何操作并返回false。否则,它将其设置为newValueOfA并返回true。因此,如果它返回true,则在您忙于调用A时,您知道没有其他人更改is_valid。如果它返回false,那么你还没有真正做过任何事情,所以你可以自由地回去再试一次。

请注意is_valid可能会多次调用;如果它有副作用(如在屏幕上打印消息),这是相关的。在这种情况下,您应该只使用互斥锁。

答案 1 :(得分:0)

这可能不是线程安全的,具体取决于is_valid究竟是什么。

特定内置点的目的只是执行原子减法。

考虑这段代码

A = A - B;

这不是线程安全的,因为它需要至少2个原子步骤 - A - B,然后分配回A。内置的这个解决了这个场景。