简体   繁体   English

为什么线程清理程序抱怨获取/释放线程围栏?

[英]Why does the thread sanitizer complain about acquire/release thread fences?

I'm learning about different memory orders.我正在了解不同的 memory 订单。

I have this code, which works and passes GCC's and Clang's thread sanitizers :我有这段代码,它可以工作并通过 GCC 和 Clang 的线程消毒剂

#include <atomic>
#include <iostream>
#include <future>
    
int state = 0;
std::atomic_int a = 0;

void foo(int from, int to) 
{
    for (int i = 0; i < 10; i++)
    {
        while (a.load(std::memory_order_acquire) != from) {}
        state++;
        a.store(to, std::memory_order_release);
    }
}

int main()
{    
    auto x = std::async(std::launch::async, foo, 0, 1);
    auto y = std::async(std::launch::async, foo, 1, 0);
}

I reckon that an 'acquire' load is unnecessary if it doesn't end up returning from , so I decided to use a 'relaxed' load, followed by an 'acquire' fence.我认为如果“获取”负载最终没有from .

I expected it to work, but it's rejected by the thread sanitizers , which claim that concurrent state++ s are a data race.我希望它能够工作,但它被 thread sanitizers 拒绝,它声称并发state++是数据竞争。

#include <atomic>
#include <iostream>
#include <future>
    
int state = 0;
std::atomic_int a = 0;

void foo(int from, int to) 
{
    for (int i = 0; i < 10; i++)
    {
        while (a.load(std::memory_order_relaxed) != from) {}
        std::atomic_thread_fence(std::memory_order_acquire);
        state++;
        a.store(to, std::memory_order_release);
    }
}

int main()
{    
    auto x = std::async(std::launch::async, foo, 0, 1);
    auto y = std::async(std::launch::async, foo, 1, 0);
}

Why is this a data race?为什么这是一场数据竞赛?

Cppreference says thatCppreference

Atomic-fence synchronization原子栅同步

An atomic release operation X in thread A synchronizes-with an acquire fence F in thread B, if线程 A 中的原子释放操作 X 与线程 B 中的获取栅栏 F 同步,如果

  • there exists an atomic read Y (with any memory order)存在原子读取 Y(使用任何 memory 顺序)
  • Y reads the value written by X (or by the release sequence headed by X) Y 读取 X 写入的值(或以 X 为首的释放序列)
  • Y is sequenced-before F in thread B Y 在线程 B 中排在 F 之前

In this case, all non-atomic and relaxed atomic stores that are sequenced-before X in thread A will happen-before all non-atomic and relaxed atomic loads from the same locations made in thread B after F.在这种情况下,在线程 A 中的 X 之前排序的所有非原子和松弛原子存储将发生在 F 之后线程 B 中相同位置的所有非原子和松弛原子加载之前。

In my understanding, all conditions are met:据我了解,所有条件都满足:

  • "there exists an atomic read Y (with any memory order)" — check: a.load(std::memory_order_relaxed) . “存在原子读取 Y(具有任何 memory 顺序)” - 检查: a.load(std::memory_order_relaxed)
  • "Y reads the value written by X" — check, it reads the value from a.store(to, std::memory_order_release); "Y 读取 X 写入的值" — 检查,它从a.store(to, std::memory_order_release); . .
  • "Y is sequenced-before F in thread B" — check. “Y 在线程 B 中排在 F 之前”——检查。

The thread sanitizer currently doesn't support std::atomic_thread_fence .线程清理程序当前不支持std::atomic_thread_fence (GCC and Clang use the same thread sanitizer, so it applies to both.) (GCC 和 Clang 使用相同的线程消毒剂,所以它适用于两者。)

GCC 12 (currently trunk) warns about it: GCC 12(当前主干)警告它:

atomic_base.h:133:26: warning: 'atomic_thread_fence' is not supported with '-fsanitize=thread' [-Wtsan]
  133 |   { __atomic_thread_fence(int(__m)); }
      |     ~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~

To stop the sanitizer from disregarding fences, you can manually instrument them, using __tsan_acquire and __tsan_release .要阻止 sanitizer 忽略栅栏,您可以使用__tsan_acquire__tsan_release手动检测它们。

#include <sanitizer/tsan_interface.h>

while (a.load(std::memory_order_relaxed) != from) {}
__tsan_acquire(&a); // <--
std::atomic_thread_fence(std::memory_order_acquire);

I assume it's tricky to automatically determine which atomic variables are affected by the fence.我认为自动确定哪些原子变量受围栏影响是很棘手的。

Even though the bug report says seq_cst fences are not affected , the code is still rejected if I use such a fence, and I'm not sure how to instrument it correctly.即使错误报告说seq_cst栅栏不受影响,如果我使用这样的栅栏,代码仍然会被拒绝,而且我不确定如何正确检测它。 Maybe __tsan_acquire + __tsan_release are enough.也许__tsan_acquire + __tsan_release就足够了。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM