简体   繁体   English

如果跨 2 个线程使用,是否值得将 size_t 声明为 std::atomic?

[英]Is is worth to declare a size_t as std::atomic if used across 2 threads?

I have a size_t variable which is updated by a std::thread and read by another std::thread .我有一个size_t变量,它由std::thread更新并由另一个std::thread读取。

I know that I can mutex protect the reads and writes.我知道我可以互斥保护读取和写入。 But, would it be the same or would it be beneficial if I make the size_t as std::atomic<size_t> ?但是,如果我将size_t设为std::atomic<size_t> ,它会是一样的还是有益的?

Yes, it is worth it.是的,这是值得的。 In fact it is mandatory to use std::atomic or synchronize access to a non-atomic if multiple threads use the same variable and at least one is writing to the variable.事实上,如果多个线程使用同一个变量并且至少有一个正在写入该变量,则必须使用std::atomic或同步对非原子的访问。 Not following this rule is data-race undefined behavior.不遵守此规则是数据竞争未定义行为。

Depending on your use of the std::size_t the compiler can assume that non-atomic and otherwise non-synchronized variables will not change from other threads and optimize the code accordingly.根据您对std::size_t的使用,编译器可以假设非原子和其他非同步变量不会从其他线程更改并相应地优化代码。 This can cause Bad Things™ to happen.这可能会导致 Bad Things™ 发生。

My usual example for this is a loop where a non-atomic boolean is used:我通常的例子是一个使用非原子布尔值的循环:

// make keepRunning an std::atomic<bool> to avoid endless loop
bool keepRunning {true};
unsigned number = 0;

void stop()
{
    keepRunning = false;
}

void loop()
{
    while(keepRunning) {
        number += 1;
    }
}

When compiling this code with optimizations enabled, GCC and Clang will both only check keepRunning once and then start an endless loop.在启用优化的情况下编译此代码时,GCC 和 Clang 都只会检查keepRunning一次,然后开始无限循环。 See https://godbolt.org/z/GYMiLE for the generated assembler output.有关生成的汇编器输出,请参阅https://godbolt.org/z/GYMiLE

ie they optimize it into if (keepRunning) infinite_loop;即他们将其优化为if (keepRunning) infinite_loop; , hoisting the load out of the loop. ,将负载提升到环路之外。 Because it's non-atomic, they're allowed to assume no other thread can be writing it.因为它是非原子的,所以他们可以假设没有其他线程可以编写它。 See Multithreading program stuck in optimized mode but runs normally in -O0 for a more detailed look at the same problem.有关同一问题的更详细信息,请参阅多线程程序卡在优化模式但在 -O0 中正常运行

Note that this example only shows the error if the loop body is sufficiently simple.请注意,此示例仅在循环体足够简单时才显示错误。 However the undefined behaviour is still present and should be avoided by using std::atomic or synchronization.然而,未定义的行为仍然存在,应该通过使用 std::atomic 或同步来避免。


In this case you can use std::atomic<bool> with std::memory_order_relaxed because you don't need any synchronization or ordering wrt.在这种情况下,您可以将std::atomic<bool>std::memory_order_relaxed因为您不需要任何同步或排序 wrt。 other operations in either the writing or reading thread.写入或读取线程中的其他操作。 That will give you atomicity (no tearing) and the assumption that the value can change asynchronously, without making the compiler use any asm barrier instructions to create more ordering wrt.这将为您提供原子性(无撕裂)并假设该值可以异步更改,而无需让编译器使用任何 asm 屏障指令来创建更多排序 wrt。 other operations.其他操作。

So it's possible and safe to use atomics without any synchronization, and without even creating synchronization between the writer and reader the way seq_cst or acquire/release loads and stores do.因此,在没有任何同步的情况下使用原子是可能且安全的,甚至不需要像 seq_cst 或获取/释放加载和存储那样在写入器和读取器之间创建同步。 You can use this synchronization to safely share a non-atomic variable or array, eg with atomic<int*> buffer that the reader reads when the pointer is non-NULL.您可以使用此同步来安全地共享非原子变量或数组,例如,当指针为非 NULL 时读取器读取的atomic<int*> buffer

But if only the atomic variable itself is shared, you can just have readers read the current value, not caring about synchronization.但是如果只有原子变量本身是共享的,你可以让读者读取当前值,而不关心同步。 You may want to read it into a local temporary if you don't need to re-read every iteration of a short loop, only once per function call.如果您不需要重新读取短循环的每次迭代,每次函数调用只需一次,您可能希望将其读入本地临时文件。

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

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