原子< bool> vs bool受互斥锁保护 [英] atomic<bool> vs bool protected by mutex

查看:362
本文介绍了原子< bool> vs bool受互斥锁保护的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们假设我们有一个内存区域,某个线程正在向其中写入数据.然后,它将注意力转移到其他位置,并允许任意其他线程读取数据.但是,在某个时间点,它希望重用该存储区并再次写入该存储区.

Let's assume we have a memory area where some thread is writing data to. It then turns its attention elsewhere and allows arbitrary other threads to read the data. However, at some point in time, it wants to reuse that memory area and will write to it again.

writer线程提供一个布尔标志(valid),该标志指示该内存仍可从中读取(即,他尚未重用它).在某个时候,他会将此标志设置为false,再也不会将其设置为true(它只会翻转一次,就是这样).

The writer thread supplies a boolean flag (valid), which indicates that the memory is still valid to read from (i.e. he is not reusing it yet). At some point he will set this flag to false and never set it to true again (it just flips once and that is it).

具有顺序一致性,分别对作者和读者使用以下两个代码段应该是正确的:

With sequential consistency, it should be correct to use these two code snippets for the writer and the readers, respectively:

...
valid = false;
<write to shared memory>
...

...
<read from shared memory>
if (valid) {
    <be happy and work with data read>
} else {
    <be sad and do something else>
}
...

显然,我们需要采取一些措施来确保顺序一致性,即插入必要的获取和释放内存屏障.我们希望在写入器线程中,在写入任何数据之前,将该标志设置为false.并且我们希望在 检查valid之前,从读取器线程中的内存中读取数据.后者是因为我们知道单调是有效的,也就是说,如果 阅读后仍然有效,则在阅读时是有效的.

We obviously need to do something to ensure sequential consistency, namely insert the necessary acquire and release memory barriers. We want the flag to be set to false in the writer thread, before writing any data to the segment. And we want the data to be read from memory in the reader threads before checking valid. The later because we know valid to be monotonic, i.e., if it is still valid after reading, it was valid while reading.

在内存访问和对valid的访问之间插入一个完整的围栏就可以解决问题.但是,我想知道,使valid成为原子原子是否足够?

Inserting a full fence between memory access and the access to valid will do the trick. I wonder, however, if making valid an atomic will be enough?

std::atomic<bool> valid = true;

然后

...
valid.store(false); // RELEASE
<write to shared memory>
...

...
<read from shared memory>
if (valid.load()) { // ACQUIRE
    <be happy and work with data read>
} else {
    <be sad and do something else>
}
...

在这种情况下,似乎暗示着通过使用原子存储进行的释放和获取操作以及对我的读取工作.编写器中的RELEASE不会阻止内存访问在其上移(只是从上面的代码可能不会移下).同样,阅读器中的ACQUIRE不会不会阻止将内存访问权移到上面(只是下面的代码可能不会被提升).

It seems that in this scenario, the implied release and acquire operations from using the the atomic store and read work against me. The RELEASE in the writer does not prevent the memory access to be moved up over it (just code from above may not be moved down). And similarly, the ACQUIRE in the readers does not prevent the memory access to be moved down over it (just code from below may not be moved up).

如果这是真的,要使此方案正常工作,我还将需要在写入器线程中进行ACQUIRE(即加载),并在读取器线程中需要进行RELEASE(即存储).或者,我可以只使用一个普通的布尔标志,并使用共享的互斥锁保护线程中的写和读访问(仅对它!).这样,我将在两个线程中同时拥有ACQUIRE和RELEASE,将valid访问与内存访问分开.

If this is true, to make this scenario work, I would need an ACQUIRE (i.e. a load) in the writer thread as well and a RELEASE (i.e. store) in the reader threads. Alternatively, I could just use a normal boolean flag and protect the write and read access (to it only!) in the threads with a shared mutex. By doing so I would effectively also have both an ACQUIRE and a RELEASE in both threads, separating the valid access from the memory access.

所以atomic<bool>与受mutex保护的常规bool之间的区别非常大,对吗?

So this would be a very severe difference between atomic<bool> and a regular bool protected by a mutex, is this correct?

编辑:实际上,原子的负载和存储对暗示的内容实际上有所不同. C ++ 11的std::atomic都将memory_order_seq_cst用作(!),而不是分别将memory_order_acquirememory_order_release用作加载和存储.

Edit: There actually seems to be a difference in what is implied by a load and a store on atomics. The std::atomic of C++11 uses memory_order_seq_cst for both (!), rather than memory_order_acquire and memory_order_release for load and store respectively.

相反,tbb::atomic使用memory_semantics::acquirememory_semantics::release而不是memory_semantics::full_fence.

因此,如果我的理解是正确的,则使用标准C ++ 11原子的代码将是正确的,但是使用tbb原子的代码将需要在加载和存储中都添加显式的memory_semantics::full_fence模板参数.

So if my understanding is correct, the code would be correct with standard C++11 atomics, but with tbb atomics one would need to add the explicit memory_semantics::full_fence template parameter to both load and store.

推荐答案

写程序将valid标志切换为false并开始写数据,而读者可能仍在读取它.

The writer switches the valid flag to false and starts writing data, while a reader might still be reading from it.

设计缺陷在于错误的假设,即只要读取器在完成读取后检查数据有效性,就不会对同一存储区进行读写操作.

The design flaw is in the incorrect assumption that reading from and writing to the same memory area is not a problem as long as the reader checks data validity once it has finished reading.

C ++标准将其称为数据竞争,并导致未定义的行为.

The C++ standard calls it a data race and it leads to undefined behavior.

正确的解决方案是使用std::shared_mutex来管理对单个写入器和多个读取器的访问.

A correct solution is to use a std::shared_mutex which manages access to a single writer and multiple readers.

这篇关于原子&lt; bool&gt; vs bool受互斥锁保护的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆