- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我想编写可移植代码(Intel、ARM、PowerPC...)来解决一个经典问题的变体:
Initially: X=Y=0
Thread A:
X=1
if(!Y){ do something }
Thread B:
Y=1
if(!X){ do something }
something
的情况。 . (如果两个都没有运行也没关系;这不是只运行一次的机制。)
memory_order_seq_cst
实现目标。原子
store
s 和
load
s 如下:
std::atomic<int> x{0},y{0};
void thread_a(){
x.store(1);
if(!y.load()) foo();
}
void thread_b(){
y.store(1);
if(!x.load()) bar();
}
{x.store(1), y.store(1), y.load(), x.load()}
事件,必须与程序顺序“边缘”一致:
x.store(1)
“在TO之前”y.load()
y.store(1)
“在TO之前”x.load()
foo()
被调用,然后我们有额外的优势:
y.load()
“读取之前的值”y.store(1)
bar()
被调用,然后我们有额外的优势:
x.load()
“读取之前的值”x.store(1)
x.store(1)
“在TO之前”
y.load()
“读取之前的值”
y.store(1)
“在TO之前”
x.load()
“读取之前的值”
x.store(true)
happens-before
这样的标准术语。 ,因为我想征求关于我假设这些边确实暗示
happens-before
的正确性的反馈。关系,可以在单个图中组合在一起,并且这种组合图中的循环是禁止的。我不确定。我所知道的是这段代码在 Intel gcc & clang 和 ARM gcc 上产生了正确的障碍
seq_cst
弱。
set()
和
check()
使得
check()
返回
true
“之后”另一个线程调用了
set()
. (也知道
set
和
check
是线程安全的,不能创建数据竞争 UB。)
set()
有点像 "X=1"和
check()
就像“X”,但我无法直接访问所涉及的原子(如果有的话)。
void thread_a(){
set();
if(!y.load()) foo();
}
void thread_b(){
y.store(1);
if(!check()) bar();
}
set()
可能在内部实现为
x.store(1,std::memory_order_release)
和/或
check()
可能是
x.load(std::memory_order_acquire)
.或者假设是
std::mutex
一个线程正在解锁,另一个线程是
try_lock
ing;在 ISO 标准中
std::mutex
只保证有获取和释放顺序,而不是 seq_cst。
check()
的 if 正文可以在
y.store(true)
之前“重新排序” (请参阅
Alex's answer,他们证明这种情况发生在 PowerPC 上)。
thread_b()
首先加载 x
的旧值( 0
) thread_a()
执行一切,包括 foo()
thread_b()
执行一切,包括 bar()
foo()
和 bar()
被叫了,我不得不避免。我有什么选择可以防止这种情况发生?
std::atomic_thread_fence(std::memory_order_seq_cst);
来实现。 - 正如
Alex in a different answer 所解释的所有经过测试的编译器都发出了完整的围栏:
- x86_64: MFENCE
- PowerPC: hwsync
- Itanuim: mf
- ARMv7 / ARMv8: dmb ish
- MIPS64: sync
std::atomic_thread_fence(std::memory_order_seq_cst)
必须转换为完整的内存屏障。其实
atomic_thread_fence
的概念C++ 中的 s 似乎处于与内存屏障的汇编概念不同的抽象级别,并且更多地处理诸如“什么原子操作与什么同步”之类的东西。是否有任何理论证据表明以下实现实现了目标?
void thread_a(){
set();
std::atomic_thread_fence(std::memory_order_seq_cst)
if(!y.load()) foo();
}
void thread_b(){
y.store(true);
std::atomic_thread_fence(std::memory_order_seq_cst)
if(!check()) bar();
}
void thread_a(){
set();
if(!y.fetch_add(0,std::memory_order_acq_rel)) foo();
}
void thread_b(){
y.exchange(1,std::memory_order_acq_rel);
if(!check()) bar();
}
y
)的访问必须形成所有观察者都同意的单一顺序,因此
fetch_add
之前
exchange
反之亦然。
fetch_add
之前
exchange
然后是
fetch_add
的“释放”部分与
exchange
的“获取”部分同步以及
set()
的所有副作用必须对执行的代码可见
check()
, 所以
bar()
不会被调用。
exchange
之前
fetch_add
,然后是
fetch_add
会看到
1
而不是打电话
foo()
.
foo()
和
bar()
.这个推理正确吗?
void thread_a(){
std::atomic<int> dummy1{};
set();
dummy1.store(13);
if(!y.load()) foo();
}
void thread_b(){
std::atomic<int> dummy2{};
y.store(1);
dummy2.load();
if(!check()) bar();
}
atomic
s 是本地的,然后想象将它们移动到全局范围,在下面的推理中,这对我来说似乎无关紧要,我故意以这种方式编写代码来暴露 dummy1 和 dummy2 完全分开是多么有趣。
{dummy1.store(13), y.load(), y.store(1), dummy2.load()}
的单个总订单这必须与程序顺序“边缘”一致:
dummy1.store(13)
“在TO之前”y.load()
y.store(1)
“在TO之前”dummy2.load()
y.store(1)
之前
y.load()
或在总顺序之后。
y.store(1)
之前
y.load()
然后
foo()
不会被召唤,我们很安全。
y.load()
之前
y.store(1)
,然后将它与我们在程序顺序中已有的两条边结合起来,我们推断出:
dummy1.store(13)
“在TO之前”dummy2.load()
dummy1.store(13)
是释放操作,释放
set()
的效果, 和
dummy2.load()
是一个获取操作,所以
check()
应该会看到
set()
的效果因此
bar()
不会被召唤,我们很安全。
check()
是否正确?会看到
set()
的结果?
我可以像这样组合各种“边缘”(“程序顺序”又名“Sequenced Before”、“总顺序”、“发布前”、“获取后”)吗? 我对此表示严重怀疑:C++ 规则似乎在谈论同一位置上存储和加载之间的“同步”关系——这里没有这种情况。
dumm1.store
的情况已知(通过其他推理)在
dummy2.load
之前在 seq_cst 总顺序中。因此,如果他们一直在访问同一个变量,负载就会看到存储的值并与之同步。
dummy2.load
之后的其他线程肯定会在
y.store
之后可见。对于另一个线程类似,...之前
y.load
。)
最佳答案
选项 A 和 B 是有效的解决方案。
dummy1
和
dummy2
.但是这些不能用于建立一个发生在之前的关系。事实上,由于原子变量是纯粹的局部变量(即,它们只被一个线程触及),编译器可以根据 as-if 规则自由地删除它们。
set()
和
check()
对一些原子值进行操作。那么我们有以下情况(->表示sequential-before):
set()
-> fence1(seq_cst)
-> y.load()
y.store(true)
-> fence2(seq_cst)
-> check()
For atomic operations A and B on an atomic object M, where A modifies M and B takes its value, if there are
memory_order_seq_cst
fences X and Y such that A is sequenced before X, Y is sequenced before B, and X precedes Y in S, then B observes either the effects of A or a later modification of M in its modification order.
check()
看到存储在
set
中的值, 或
y.load()
看到写入的值是
y.store()
(对
y
的操作甚至可以使用
memory_order_relaxed
)。
There shall be a single total order S on all
memory_order_seq_cst
operations, consistent with the "happens before" order and modification orders for all affected locations [...]
关于c++ - 如何在 C++11 中实现 StoreLoad 屏障?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60053973/
背景: 我最近一直在使用 JPA,我为相当大的关系数据库项目生成持久层的轻松程度给我留下了深刻的印象。 我们公司使用大量非 SQL 数据库,特别是面向列的数据库。我对可能对这些数据库使用 JPA 有一
我已经在我的 maven pom 中添加了这些构建配置,因为我希望将 Apache Solr 依赖项与 Jar 捆绑在一起。否则我得到了 SolarServerException: ClassNotF
interface ITurtle { void Fight(); void EatPizza(); } interface ILeonardo : ITurtle {
我希望可用于 Java 的对象/关系映射 (ORM) 工具之一能够满足这些要求: 使用 JPA 或 native SQL 查询获取大量行并将其作为实体对象返回。 允许在行(实体)中进行迭代,并在对当前
好像没有,因为我有实现From for 的代码, 我可以转换 A到 B与 .into() , 但同样的事情不适用于 Vec .into()一个Vec . 要么我搞砸了阻止实现派生的事情,要么这不应该发
在 C# 中,如果 A 实现 IX 并且 B 继承自 A ,是否必然遵循 B 实现 IX?如果是,是因为 LSP 吗?之间有什么区别吗: 1. Interface IX; Class A : IX;
就目前而言,这个问题不适合我们的问答形式。我们希望答案得到事实、引用资料或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visit the
我正在阅读标准haskell库的(^)的实现代码: (^) :: (Num a, Integral b) => a -> b -> a x0 ^ y0 | y0 a -> b ->a expo x0
我将把国际象棋游戏表示为 C++ 结构。我认为,最好的选择是树结构(因为在每个深度我们都有几个可能的移动)。 这是一个好的方法吗? struct TreeElement{ SomeMoveType
我正在为用户名数据库实现字符串匹配算法。我的方法采用现有的用户名数据库和用户想要的新用户名,然后检查用户名是否已被占用。如果采用该方法,则该方法应该返回带有数据库中未采用的数字的用户名。 例子: “贾
我正在尝试实现 Breadth-first search algorithm , 为了找到两个顶点之间的最短距离。我开发了一个 Queue 对象来保存和检索对象,并且我有一个二维数组来保存两个给定顶点
我目前正在 ika 中开发我的 Python 游戏,它使用 python 2.5 我决定为 AI 使用 A* 寻路。然而,我发现它对我的需要来说太慢了(3-4 个敌人可能会落后于游戏,但我想供应 4-
我正在寻找 Kademlia 的开源实现C/C++ 中的分布式哈希表。它必须是轻量级和跨平台的(win/linux/mac)。 它必须能够将信息发布到 DHT 并检索它。 最佳答案 OpenDHT是
我在一本书中读到这一行:-“当我们要求 C++ 实现运行程序时,它会通过调用此函数来实现。” 而且我想知道“C++ 实现”是什么意思或具体是什么。帮忙!? 最佳答案 “C++ 实现”是指编译器加上链接
我正在尝试使用分支定界的 C++ 实现这个背包问题。此网站上有一个 Java 版本:Implementing branch and bound for knapsack 我试图让我的 C++ 版本打印
在很多情况下,我需要在 C# 中访问合适的哈希算法,从重写 GetHashCode 到对数据执行快速比较/查找。 我发现 FNV 哈希是一种非常简单/好/快速的哈希算法。但是,我从未见过 C# 实现的
目录 LRU缓存替换策略 核心思想 不适用场景 算法基本实现 算法优化
1. 绪论 在前面文章中提到 空间直角坐标系相互转换 ,测绘坐标转换时,一般涉及到的情况是:两个直角坐标系的小角度转换。这个就是我们经常在测绘数据处理中,WGS-84坐标系、54北京坐标系
在软件开发过程中,有时候我们需要定时地检查数据库中的数据,并在发现新增数据时触发一个动作。为了实现这个需求,我们在 .Net 7 下进行一次简单的演示. PeriodicTimer .
二分查找 二分查找算法,说白了就是在有序的数组里面给予一个存在数组里面的值key,然后将其先和数组中间的比较,如果key大于中间值,进行下一次mid后面的比较,直到找到相等的,就可以得到它的位置。
我是一名优秀的程序员,十分优秀!