- mongodb - 在 MongoDB mapreduce 中,如何展平值对象?
- javascript - 对象传播与 Object.assign
- html - 输入类型 ="submit"Vs 按钮标签它们可以互换吗?
- sql - 使用 MongoDB 而不是 MS SQL Server 的优缺点
我目前正在阅读 Anthony Williams 的 C++ Concurrency in Action。他的一个 list 显示了这段代码,他声明了 z != 0
的断言。可以火。
#include <atomic>
#include <thread>
#include <assert.h>
std::atomic<bool> x,y;
std::atomic<int> z;
void write_x()
{
x.store(true,std::memory_order_release);
}
void write_y()
{
y.store(true,std::memory_order_release);
}
void read_x_then_y()
{
while(!x.load(std::memory_order_acquire));
if(y.load(std::memory_order_acquire))
++z;
}
void read_y_then_x()
{
while(!y.load(std::memory_order_acquire));
if(x.load(std::memory_order_acquire))
++z;
}
int main()
{
x=false;
y=false;
z=0;
std::thread a(write_x);
std::thread b(write_y);
std::thread c(read_x_then_y);
std::thread d(read_y_then_x);
a.join();
b.join();
c.join();
d.join();
assert(z.load()!=0);
}
Thread a (x is now true)
Thread c (fails to increment z)
Thread b (y is now true)
Thread d (increments z) assertion cannot fire
Thread b (y is now true)
Thread d (fails to increment z)
Thread a (x is now true)
Thread c (increments z) assertion cannot fire
Thread a (x is true)
Thread b (y is true)
Thread c (z is incremented) assertion cannot fire
Thread d (z is incremented)
y
还与
read_x_then_y
中的负载同步,和店铺到
x
与负载同步
read_y_then_x
?我很困惑。
thread a
(
write_x
) 存储到
x
然后它到目前为止所做的所有工作都与读取
x
的任何其他线程同步。与获取订购。曾经
read_x_then_y
看到这一点,它跳出循环并读取
y
.现在,可能会发生两件事。在一种选择中,
write_y
已写信给
y
, 表示此版本将与 if 语句 (load) 同步,意思是
z
递增并且断言不能触发。另一个选项是如果
write_y
还没有运行,这意味着 if 条件失败并且 z 没有增加,在这种情况下,只有
x
是真的和
y
仍然是假的。一旦 write_y 运行,read_y_then_x 就会跳出它的循环,但是两者都是
x
和
y
是真的和
z
递增并且断言不会触发。我想不出任何“运行”或内存排序在哪里
z
永远不会增加。有人可以解释我的推理哪里有缺陷吗?
最佳答案
您正在考虑顺序一致性,即最强(和默认)的内存顺序。如果使用这个内存顺序,所有对原子变量的访问构成一个全序,断言确实不能触发。
然而,在这个程序中,使用了较弱的内存顺序(释放存储和获取加载)。这意味着,根据定义,您不能假设操作的总顺序。特别是,您不能假设更改对其他线程以相同的顺序可见。 (对于任何原子内存顺序,仅保证每个单独变量的总顺序,包括 memory_order_relaxed
。)
本店至x
和 y
发生在不同的线程上,它们之间没有同步。 x
的负载和 y
发生在不同的线程上,它们之间没有同步。这意味着完全允许线程 c 看到 x && ! y
和线程 d 看到 y && ! x
. (我只是在此处缩写了获取加载,不要将此语法视为顺序一致的加载。)
底线:一旦您使用比顺序一致更弱的内存顺序,您就可以亲吻所有原子的全局状态的概念,即所有线程之间一致,再见。这正是为什么这么多人建议坚持顺序一致性的原因,除非您需要性能(顺便说一句,请记住衡量它是否更快!)并且确定您在做什么。另外,获得第二意见。
现在,你是否会被这个烧伤,是一个不同的问题。该标准仅允许基于用于描述标准要求的抽象机器的断言失败的场景。但是,由于某种原因,您的编译器和/或 CPU 可能不会利用此限额。因此,对于给定的编译器和 CPU,您可能永远不会在实践中看到触发了断言。请记住,编译器或 CPU 可能总是使用比您要求的更严格的内存顺序,因为这永远不会违反标准的最低要求。它可能只会让您损失一些性能——但无论如何标准都没有涵盖这一点。
更新以回应评论:该标准没有定义一个线程看到另一个线程对原子的更改所需的时间上限。向实现者建议值最终应该变得可见。
有顺序保证,但与您的示例相关的保证不会阻止断言触发。基本的获取-释放保证是,如果:
x
x
, 对 f 中的任何操作都是可见的,也就是说,在这个线程中,在给定的负载之后排序。 [请注意,除了这两个线程之外,不提供任何保证!] x
的一些旧值.如果它不读取更新的值,那么加载也不会与存储同步,并且上面提到的任何依赖操作都没有顺序保证。
atomic<unsigned>
的周期性增量(例如使用释放顺序)变量,初始化为 0,另一个线程周期性地从这个变量加载(例如,使用获取顺序),然后,除了最终包装外,后一个线程看到的值必须单调增加。但这遵循给定的排序规则:一旦后一个线程读取 5,在从 4 到 5 的增量之前发生的任何事情都是在读取 5 之后的任何事情的相对过去。 事实上,除了换行之外的减少是甚至不允许
memory_order_relaxed
,但是这个内存顺序并没有对访问其他变量的相对顺序(如果有的话)做出任何 promise 。
关于c++ - 使用 4 个线程获取/释放语义,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48383867/
我需要您在以下方面提供帮助。近一个月来,我一直在阅读有关任务和异步的内容。 我想尝试在一个简单的 wep api 项目中实现我新获得的知识。我有以下方法,并且它们都按预期工作: public Htt
我的可执行 jar 中有一个模板文件 (.xls)。不需要在运行时我需要为这个文件创建 100 多个副本(稍后将唯一地附加)。用于获取 jar 文件中的资源 (template.xls)。我正在使用
我在查看网站的模型代码时对原型(prototype)有疑问。我知道这对 Javascript 中的继承很有用。 在这个例子中... define([], function () { "use
影响我性能的前三项操作是: 获取滚动条 获取偏移高度 Ext.getStyle 为了解释我的应用程序中发生了什么:我有一个网格,其中有一列在每个单元格中呈现网格。当我几乎对网格的内容做任何事情时,它运
我正在使用以下函数来获取 URL 参数。 function gup(name, url) { name = name.replace(/[\[]/, '\\\[').replace(/[\]]/,
我最近一直在使用 sysctl 来做很多事情,现在我使用 HW_MACHINE_ARCH 变量。我正在使用以下代码。请注意,当我尝试获取其他变量 HW_MACHINE 时,此代码可以完美运行。我还认为
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 关闭 9 年前。 要求提供代码的问题必须表现出对所解决问题的最低限度的理解。包括尝试过的解决方案、为什么
由于使用 main-bower-files 作为使用 Gulp 的编译任务的一部分,我无法使用 node_modules 中的 webpack 来require 模块code> dir 因为我会弄乱当
关闭。这个问题需要更多focused .它目前不接受答案。 想改进这个问题吗? 更新问题,使其只关注一个问题 editing this post . 关闭 5 年前。 Improve this qu
我使用 Gridlayout 在一行中放置 4 个元素。首先,我有一个 JPanel,一切正常。对于行数变大并且我必须能够向下滚动的情况,我对其进行了一些更改。现在我的 JPanel 上添加了一个 J
由于以下原因,我想将 VolumeId 的值保存在变量中: #!/usr/bin/env python import boto3 import json import argparse import
我正在将 MSAL 版本 1.x 更新为 MSAL-browser 的 Angular 。所以我正在尝试从版本 1.x 迁移到 2.X.I 能够成功替换代码并且工作正常。但是我遇到了 acquireT
我知道有很多关于此的问题,例如 Getting daily averages with pandas和 How get monthly mean in pandas using groupby但我遇到
This is the query string that I am receiving in URL. Output url: /demo/analysis/test?startDate=Sat+
我正在尝试使用 javascript 中的以下代码访问 Geoserver 层 var gkvrtWmsSource =new ol.source.ImageWMS({ u
API 需要一个包含授权代码的 header 。这就是我到目前为止所拥有的: var fullUrl = 'https://api.ecobee.com/1/thermostat?json=\{"s
如何获取文件中的最后一个字符,如果是某个字符,则删除它而不将整个文件加载到内存中? 这就是我目前所拥有的。 using (var fileStream = new FileStream("file.t
我是这个社区的新手,想出了我的第一个问题。 我正在使用 JSP,我成功地创建了 JSP-Sites,它正在使用jsp:setParameter 和 jsp:getParameter 具有单个字符串。
在回答 StoreStore reordering happens when compiling C++ for x86 @Peter Cordes 写过 For Acquire/Release se
我有一个函数,我们将其命名为 X1,它返回变量 Y。该函数在操作 .on("focusout", X1) 中使用。如何获取变量Y?执行.on后X1的结果? 最佳答案 您可以更改 Y 的范围以使其位于函
我是一名优秀的程序员,十分优秀!