- mongodb - 在 MongoDB mapreduce 中,如何展平值对象?
- javascript - 对象传播与 Object.assign
- html - 输入类型 ="submit"Vs 按钮标签它们可以互换吗?
- sql - 使用 MongoDB 而不是 MS SQL Server 的优缺点
C++0x draft有一个栅栏的概念,这似乎与 CPU/芯片级别的栅栏概念非常不同,或者说 linux 内核人员对 fences 的期望.问题是草案是否真的暗示了一个极其受限的模型,或者措辞很差,实际上暗示了真正的围栏。
例如,在 29.8 Fences 下,它声明如下:
A release fence A synchronizes with an acquire fence B if there exist atomic operations X and Y, both operating on some atomic object M, such that A is sequenced before X, X modifies M, Y is sequenced before B, and Y reads the value written by X or a value written by any side effect in the hypothetical release sequence X would head if it were a release operation.
它使用这些术语 atomic operations
和 atomic object
.草案中定义了这样的原子操作和方法,但是否仅指这些? 发布围栏听起来像商店围栏。不保证在栅栏之前写入所有数据的存储栅栏几乎是无用的。加载(获取)栅栏和完整栅栏类似。
那么,C++0x 中的栅栏/障碍是正确的栅栏和措辞非常糟糕,还是如描述的那样受到严格限制/无用?
就 C++ 而言,假设我有这个现有代码(假设栅栏现在可用作高级构造——而不是说在 GCC 中使用 __sync_synchronize):
Thread A:
b = 9;
store_fence();
a = 5;
Thread B:
if( a == 5 )
{
load_fence();
c = b;
}
假设 a,b,c 的大小可以在平台上进行原子复制。以上表示c
只会被分配 9
.请注意,我们不在乎线程 B 何时看到 a==5
, 只是当它执行时它也会看到 b==9
.
C++0x中保证相同关系的代码是什么?
回答:如果您阅读了我选择的答案和所有评论,您将了解情况的要点。 C++0x 似乎迫使您使用带栅栏的原子,而普通的硬件栅栏没有这个要求。在许多情况下,只要 sizeof(atomic<T>) == sizeof(T)
,它仍然可以用来替换并发算法。和 atomic<T>.is_lock_free() == true
.
不幸的是is_lock_free
不是 constexpr。这将允许它在 static_assert
中使用。 .有atomic<T>
退化为使用锁通常是一个坏主意:与使用互斥锁设计的算法相比,使用互斥锁的原子算法将存在可怕的争用问题。
最佳答案
栅栏对所有数据提供排序。但是,为了保证一个线程的栅栏操作对第二个线程可见,需要对标志使用原子操作,否则会出现数据竞争。
std::atomic<bool> ready(false);
int data=0;
void thread_1()
{
data=42;
std::atomic_thread_fence(std::memory_order_release);
ready.store(true,std::memory_order_relaxed);
}
void thread_2()
{
if(ready.load(std::memory_order_relaxed))
{
std::atomic_thread_fence(std::memory_order_acquire);
std::cout<<"data="<<data<<std::endl;
}
}
如果 thread_2
将 ready
读取为 true
,则栅栏确保 data
可以安全地被读取,输出将是 data=42
。如果 ready
被读取为 false
,那么你不能保证 thread_1
已经发出了适当的栅栏,所以线程 2 中的栅栏仍然不会提供必要的排序保证 --- 如果 thread_2
中的 if
被省略,对 data
的访问将是数据竞争和未定义的行为,即使有栅栏。
澄清:std::atomic_thread_fence(std::memory_order_release)
通常等同于存储栅栏,并且很可能会这样实现。但是,一个处理器上的单个栅栏并不能保证任何内存排序:您需要在第二个处理器上设置相应的栅栏,并且您需要知道执行获取栅栏时释放栅栏的效果对第二个处理器可见。很明显,如果 CPU A 发出了一个获取围栏,然后 5 秒后 CPU B 发出了一个释放围栏,那么这个释放围栏就无法与获取围栏同步。除非您有某种方法可以检查是否已在其他 CPU 上发出了栅栏,否则 CPU A 上的代码无法判断它是在 CPU B 上的栅栏之前还是之后发出了栅栏。
您使用原子操作来检查是否已看到栅栏的要求是数据竞争规则的结果:您不能在没有排序关系的情况下从多个线程访问非原子变量,因此您不能使用用于检查排序关系的非原子变量。
当然可以使用更强大的机制,例如互斥锁,但这会使单独的围栏变得毫无意义,因为互斥锁会提供围栏。
宽松的原子操作可能只是现代 CPU 上的普通加载和存储,尽管可能需要额外的对齐要求以确保原子性。
如果用于检查同步的操作(而不是用于访问同步数据的操作)是原子的,那么使用特定于处理器的栅栏编写的代码可以很容易地更改为使用 C++0x 栅栏。现有代码很可能依赖于给定 CPU 上的普通加载和存储的原子性,但转换为 C++0x 将需要对这些检查使用原子操作以提供排序保证。
关于c++ - C++0x 中的栅栏,一般只保证原子或内存,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5547212/
有没有办法用连词创建原子 if ?也就是说,我可以以某种方式在 C 中自动测试 if(A && B) 吗?如果它在第一个连接处短路,那么没问题,但如果没有短路,则在检查 B 时,A 可能已更改。有什么
我有很多 fork 的过程。子进程做很多事情和另一个系统调用。 当任何子进程从系统调用中获取错误时,它会将错误描述打印到 stderr 并将 SIGUSR1 发送到组长(主要父进程)。 SIGUSR1
阅读 boost::atomic 上的文档和 std::atomic 让我感到困惑的是 atomic 是否接口(interface)应该支持非平凡类型? 也就是说,给定一个只能通过将读/写包含在一个完
我有一个命令,可以将叠加图像放在视频上。 之后,我调整输出大小以适合某些尺寸。 通常一切正常,但有时且仅在某台台式计算机上,当第二次精化开始时,命令返回错误:moov atom not found 让
我最近发现当 LANG 设置为 C.utf8 时,X11 原子 WM_NAME 未在 Swing JFrame 中设置。但为 LANG 的其他值设置。这发生在带有 OpenJDK 11.0.9 的 L
我目前正在使用blackmagic的prorecorder录制视频。我使用 ffmpeg 将视频即时转码为 mp4 视频容器。持续时间未知,因为我正在对 prorecorder 输出到命名管道的 .t
这里真的有人使用 atom 来处理 git 提交消息吗?我想但我遇到了这个问题并且一直坚持使用 git commit -m '....' 。当我尝试使用 atom 时,它会打开 atom,我几乎立即从
考虑: void foo() { std::vector> foo(10); ... } foo 的内容现在有效吗?或者我是否需要显式循环并初始化它们?我检查过 Godbolt,看起来不错,但
在official FAQ我阅读的 Memcached: “发送到 memcached 的所有单独命令都是绝对原子的。” 然而,当涉及到 get_multi 和 set_multi 时,我仍然不清楚。
在测试程序的可扩展性时,我遇到了必须将 memcpy 操作设置为原子操作的情况。我必须将 64 字节的数据从一个位置复制到另一个位置。 我遇到了一种解决方案,即使用旋转变量: struct recor
我对 C++ 原子变量感到困惑。如果我有一个原子 x,我想在一个线程中递增并在另一个线程中读取,我可以执行++x 还是必须执行 x.atomic_fetch_add(1)。在读者线程中,我可以做类似
跟进自 Multiple assignment in one line ,我很想知道这对原子数据类型是如何工作的,特别是 bool 类型的例子。 给定: class foo { std::at
我想创建一个版本控制系统,并且对版本号为 1 的新条目的查询如下所示: ID 和修订号组合起来就是主键。 insert into contentfile (id, name, revision, ac
我在 iOS 项目中有下一个独立的测试片段: /// ... std::atomic_bool ab; ab.store(true); bool expected = false; while (!a
我了解如何使用条件变量(此构造的名称很糟糕,IMO,因为 cv 对象既不是变量也不表示条件)。所以我有一对线程,canonically使用 Boost.Thread 设置为: bool awake =
因此,对于最终项目,我尝试制作一款包含三种不同 meteor 的游戏;铜牌、银牌和金牌。虽然青铜阵列在Setup()中工作正常,但银色和金色 meteor 由于某种未知原因而高速移动。 functio
第一个问题,为什么不在 atomic_compare_exchange_weak 操作的参数中应用后缀求值 (++)?运算前后a的值相同。然而,当在 printf() 中使用时,正如预期的那样,该值会
我正在尝试使用 OpenMP 对已经矢量化的代码进行内部函数并行化,但问题是我使用一个 XMM 寄存器作为外部“变量”,我会在每个循环中递增。现在我正在使用 shared 子句 __m128d xmm
clojure“atom”的文档指出 - "Changes to atoms are always free of race conditions." 但是,竞争条件不仅根据更改定义,而且在不同线程中
我一直在研究原子引用计数的实现。 库之间的大多数操作都非常一致,但我在“减少引用计数”操作中发现了惊人的多样性。 (请注意,通常情况下,shared 和 weak decref 之间的唯一区别是调用了
我是一名优秀的程序员,十分优秀!