【问题标题】:ThreadSanitizer says my Atomic Inc/Dec has data races, false positive?ThreadSanitizer 说我的 Atomic Inc/Dec 有数据竞争,误报?
【发布时间】:2016-07-07 17:28:10
【问题描述】:

我使用 asm 编写了 atomic_inc 来增加一个整数,它实际上用于引用共享对象的计数。 gcc 4.8.2 -fsanitize=thread 报告数据竞争,我终于发现这很可能是由我的 atomic_inc 引起的。我不相信我的代码存在与数据竞争有关的错误,这是 tsan 的误报吗?

static inline int atomic_add(volatile int *count, int add) {
    __asm__ __volatile__(
            "lock xadd %0, (%1);"
            : "=a"(add)
            : "r"(count), "a"(add)
            : "memory"
    );
    return add;
}

void MyClass::Ref() {
    // std::unique_lock<std::mutex> lock(s_ref);
    atomic_add(&_refs, 1);
}
void MyClass::Unref() {
    // std::unique_lock<std::mutex> lock(s_ref);
    int n = atomic_add(&_refs, -1) - 1;
    // lock.unlock();
    assert(n >= 0);
    if (n <= 0) {
        delete this;
    }
}

【问题讨论】:

  • 除了下面(到目前为止)2 个很好的答案之外,您的 asm 也是不正确的。此代码更改仅输入参数(计数)的值。如果你必须使用 asm,也许像 asm("lock xadd %[add], %[count]" : [add] "+r"(add), [count] "+m"(count) : : "memory", "cc");?

标签: c++ linux multithreading locking


【解决方案1】:

您的部分问题是 gcc 不查看 asm 内部。

问题的另一部分是volatile 不会使变量成为线程安全的。

鉴于__asm__ 表示您致力于gcc,为什么不使用gcc 内在函数? (它们已记录并经过充分测试,gcc 会理解它们的语义。)

至于警告是否是误报,我不知道。安全的做法是假设问题是真实的。 真的很难看到多线程代码中的问题(即使您知道它们就在那里)。 (有一次,我们使用已发布的互斥算法提取了一段非常聪明的代码,该算法失败了,并用一个简单的自旋锁替换它。这修复了失败,但我们永远无法找到它失败的原因。 )

【讨论】:

  • 我知道c++11左右提供了其他原子函数,但我的问题是tsan为什么抱怨我的代码,这是一个错误的抱怨吗?
  • @bugsking,您阅读答案了吗?非常清楚!发生这种情况是因为 TSAN 不知道您的 ASM 在做什么,它适用于 C++ 代码级别。是的,您应该将 gcc 内在函数用于原子(它们不是 C++11 线程的东西)。
【解决方案2】:

正如其他人已经说过的那样,该工具无法看到您的 asm 内部。但无论如何你都不应该那样做。 只需使用 std::atomic 并完成它 - 这是线程安全和可移植的,编译器知道如何优化它 - 不像你当前的代码。

【讨论】:

    猜你喜欢
    • 2022-08-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多