问题标签 [stdatomic]
For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.
c++ - 将 lock xadd 与 lock xchg 混合。有xchg的商店会迷路吗?
在 C++ 代码中,但不特定于 C++,并且可以很容易地用多种语言表示:
是否有可能执行 xadd 从存储 INT_MIN 之前读取计数器的值,然后存储 INT_MIN,并且计数器 clobbers INT_MIN 的增量值 - 因此计数器可能永远不会变为负数(假设它不会环绕,无论如何这都是未定义的。)
我想知道那个带有 xchg 的商店是否会“迷路”。如果是这样,我真的需要使用 CAS 而不是 fetch_add。但是,我怀疑由于 lock xadd 特别必须防止丢失更新,因此它的执行不能与其他线程上的锁定指令交错(至少与其他 lock xadd!)
c++ - 如何设置/获取指向结构的指针的低位?
我正在尝试为自组织列表开发无锁解决方案。我最近发现了标记指针,并认为它对我有用。
我的节点结构如下:
我想使用原子库中的 compare_exchange_strong 函数
例如,如果一个线程正在一个节点上工作,那么 cas 不应该通过,因为这个低位将不匹配。
我的问题是:
- 如何在不丢失节点具有的引用(next & val)的情况下设置此位?
- 我怎样才能把它放回去?
c++ - 向类添加仅移动类型会使该类成为仅移动类型?
在 Scott Meyers 的“Effective Modern C++”中,他写道:
毫无价值,因为
std::mutex
它是只移动类型(即可以移动但不能复制的类型),添加m
to的副作用Polynomial
是Polynomial
失去被复制的能力。但是,它仍然可以移动。
在这里,他在解释为什么应该保护对类的 const 成员变量的访问(在多线程时)的上下文中将astd::mutex m
作为成员变量添加到类中。Polynomial
我理解他解释的概念。但是我需要更多解释的一件事是“为什么向类添加仅移动类型会使该类成为仅移动类型不可复制”?为什么默认类型为仅移动类型std::mutex
?std::atomic
即使在向我们的类中添加仅移动类型的变量时,如果我们想要执行复制操作,我们如何才能克服它?
multithreading - 当有一个阅读器和一个编写器线程时,我是否需要使用 std::atomic_
我希望在读取器/写入器场景中使用 std::shared_ptr 。一个线程不断接收新信息并保持一个指向最新数据的智能指针。当需要运行我的慢速计算时,我将智能指针指向所有数据,以确保我正在查看一致的数据。在下面的示例中,当我使用 a 和 b 时,我知道它们属于一起。
我不确定我是否应该在这里使用 atomic_load 和 atomic_store ?只要它是一致且有效的,我并不关心我正在查看哪个版本的 Foo。
那么我应该在我的智能指针上使用 atomic 以便让这段代码在两个不同的线程中工作吗?
谢谢,
保罗
c++11 - std::atomic 是否保证 int、float 等类型的初始化初始化为 0/0.0?
当作为类成员创建时,std::atomic<basic_type>
保证值为0 / 0.0(以适用者为准),而无需显式初始化:basic_type
- int / uint / short / ushort / 等等...
- 和; 浮动/双
?
例子:
c++ - 内存栅栏:获取/加载和释放/存储
我对std::memory_order_acquire
和std::memory_order_release
的理解如下:
Acquire意味着在获取栅栏之后出现的任何内存访问都不能重新排序到栅栏之前。
释放意味着在释放栅栏之前出现的任何内存访问都不能重新排序到栅栏之后。
我不明白为什么特别是 C++11 原子库,获取栅栏与加载操作相关联,而释放栅栏与存储操作相关联。
澄清一下,C++11<atomic>
库允许您以两种方式指定内存栅栏:您可以将栅栏指定为原子操作的额外参数,例如:
或者您可以std::memory_order_relaxed
单独使用和指定栅栏,例如:
我不明白的是,鉴于上述acquire和release的定义,为什么C++ 11专门将acquire与load关联,将release与store关联?是的,我已经看到了许多示例,这些示例展示了如何使用获取/加载和释放/存储来在线程之间同步,但总的来说,获取栅栏(防止语句后内存重新排序)和释放的想法似乎是栅栏(在语句之前防止内存重新排序)与加载和存储的想法是正交的。
那么,例如,为什么编译器不让我说:
我意识到我可以通过使用来完成上述操作memory_order_relaxed
,然后使用单独的atomic_thread_fence(memory_order_acquire)
语句,但同样,为什么我不能直接使用 storememory_order_acquire
呢?
一个可能的用例可能是,如果我想确保某个存储,比如说,在执行可能影响其他线程的其他语句之前x = 10
发生。
c++ - GCC 使用 `memory_order_seq_cst` 跨负载重新排序。这是允许的吗?
使用基本 seqlock的简化版本,gcc 在load(memory_order_seq_cst)
使用-O3
. 使用其他优化级别编译或使用 clang(甚至 on O3
)编译时,不会观察到这种重新排序。这种重新排序似乎违反了应该建立的同步关系,我很想知道为什么 gcc 会重新排序这个特定的负载,以及标准是否允许这样做。
考虑以下load
函数:
在 seqlock 过程之后,此读取器旋转直到它能够加载 的两个实例seq_
,这两个实例被定义为 a std::atomic<std::size_t>
,它们是偶数(表示写入者当前未写入)和相等(表示写入者尚未写入value
在两个负载之间seq_
)。此外,由于这些负载被标记为memory_order_seq_cst
( 作为默认参数 ),我想该指令copy = value;
将在每次迭代时执行,因为它不能在初始负载中重新排序,也不能在后者之下重新排序。
但是,生成的程序集value
在第一次加载之前发出加载,seq_
甚至在循环之外执行。这可能导致不正确的同步或value
seqlock 算法无法解决的读取中断。此外,我注意到这只发生在 sizeof(value)
123 字节以下时。修改value
为某种类型 >= 123 字节会产生正确的程序集,并在每次循环迭代时在两次加载seq_
. 为什么这个看似任意的阈值决定了生成哪个程序集?
该测试工具 暴露了我的 Xeon E3-1505M 上的行为,其中将从阅读器打印“Observed: 2”并返回值 65535。观察到的值seq_
和返回的负载的组合value
似乎违反了应该由编写线程发布seq.store(2)
与memory_order_release
读取线程和读取线程建立的同步seq_
关系memory_order_seq_cst
。
gcc 对负载重新排序是否有效,如果是,为什么它只在sizeof(value)
< 123 时才这样做?clang,无论优化级别还是sizeof(value)
不会重新排序负载。我相信 Clang 的 codegen 是适当且正确的方法。
c++ - GCC 原子 shared_ptr 实现
根据https://gcc.gnu.org/bugzilla/show_bug.cgi?id=57250,GCC 4.9 支持原子shared_ptr
操作。
使用 GCC 4.9.2,我可以编译一个使用 atomic 的程序shared_ptr
。该-mcx16
标志是必需的,因为 x86_64 上的 GCC 实现显然需要cmpxchg16b
,这是有道理的,因为我假设 a 上的原子操作shared_ptr
将需要同时以原子方式更新指针本身和引用计数。
但是,当我尝试实际使用原子shared_ptr
库时,它的行为并不符合我的预期。所以,要么我没有正确使用它,要么 GCC 实现有缺陷。大多数时候,我有 99% 的把握认为自己做错了,但由于这是一个相对较新的功能,而且这种行为看起来很奇怪,所以我只有 50% 的把握认为这是我的错案子。
这是一个简单的程序,它创建一个 atomic shared_ptr
,然后在 shared_ptr 上执行一系列并发读取和写入:
当我编译并运行时,输出是:
但是这个输出对我来说毫无意义。首先,在将 atomic 初始化shared_ptr
为 的值之后10
,当我加载它并读取初始值(在产生任何线程之前)时,我得到一个0
. 其次,在所有线程加入后,该值仍然是0
,即使没有线程可能将其设置为0
。最奇怪的是,线程加入后,use_count()
shared_ptr 的0
! 然而,原子shared_ptr
对象仍在范围内,因此使用计数应该是1
.
我很确定 GCC 实现在这里有缺陷,但根据我上面发布的链接,GCC 4.9 有一个完整的原子shared_ptr
实现,并且......
那么......这里到底发生了什么?我想得到某种确认,即此处的 GCC 4.9.2 实现存在缺陷或不完整,或者我对如何使用 atomic 完全错误/困惑shared_ptr
。
c++ - 标准::原子在主线程中修改,但在其他线程中不变
我正在尝试使用 std::atomic 来合作停止我的国际象棋 AI 中的一些线程。当我调用 StopPondering() 时,我无法弄清楚为什么我的线程继续运行。如果我中断 StopPondering 我会看到 Searching 设置正确,但如果我中断两个线程中的任何一个,它的值仍然是 true。我在 Windows 8.1 上使用 VS 2013 代码的相关子集如下。
AI0.h
AI0.cpp
我为我不一致的大小写道歉。
- - - - -编辑 - - - - -
问题解决了。我愚蠢地创建了多个 AI0 实例,而且,正如某些人所怀疑的那样,我没有在产生线程的同一个实例上调用 StopPondering(),这肯定是内存泄漏。我现在只有一个 AI0 单例,一切都按预期工作。很抱歉失败了。
c++ - 以宽松的顺序修改原子值
假设我有以下代码片段:
问题是:我能得到0 0
结果吗?
这里两个线程都a
以宽松的内存顺序读取和修改,所以看起来它们都可以看到a
. 但在实践中,我只看到0 1
或1 0
。