草庐IT

c++ - 非原子负载可以在原子获取负载之后重新排序吗?

coder 2024-02-16 原文

众所周知,自 C++11 以来,有 6 个内存顺序,在有关 std::memory_order_acquire 的文档中:

memory_order_acquire

A load operation with this memory order performs the acquire operation on the affected memory location: no memory accesses in the current thread can be reordered before this load. This ensures that all writes in other threads that release the same atomic variable are visible in the current thread.

<强>1。非atomic-load可以在atomic-acquire-load之后重新排序:

即不保证在acquire-atomic-load之后不能重新排序non-atomic-load。

static std::atomic<int> X;
static int L;
...

void thread_func() 
{
    int local1 = L;  // load(L)-load(X) - can be reordered with X ?

    int x_local = X.load(std::memory_order_acquire);  // load(X)

    int local2 = L;  // load(X)-load(L) - can't be reordered with X
}

加载 int local1 = L; 可以在 X.load(std::memory_order_acquire); 之后重新排序吗?

<强>2。我们可以认为非atomic-load在atomic-acquire-load之后是不能重新排序的:

一些文章包含一张图片,展示了获取-释放语义的本质。这很容易理解,但会引起混淆。

例如,我们可能认为std::memory_order_acquire不能对任何一系列的Load-Load操作进行重新排序,即使是非atomic-load也不能在atomic-acquire-load之后进行重新排序.

<强>3。非atomic-load可以在atomic-acquire-load之后重新排序:

澄清的好事:获取语义可防止读取-获取的内存重新排序,任何读取或写入操作按程序顺序紧随其后http://preshing.com/20120913/acquire-and-release-semantics/

还有known, that :在强排序系统(x86、SPARC TSO、IBM 大型机)上,release-acquire 排序对于大多数操作是自动的

第 34 页的 Herb Sutter 显示:https://onedrive.live.com/view.aspx?resid=4E86B0CF20EF15AD!24884&app=WordPdf&authkey=!AMtj_EflYn2507c

<强>4。 IE。同样,我们可以认为非atomic-load不能在atomic-acquire-load之后重新排序:

即对于 x86:

  • release-acquire 排序对于大多数操作都是自动的
  • Reads 不会与 any reads 一起重新排序。 (任何 - 即无论是否年长)

那么在 C++11 中非原子加载是否可以在原子获取加载之后重新排序?

最佳答案

我相信这是在 C++ 标准中推理您的示例的正确方法:

  1. X.load(std::memory_order_acquire)(我们称之为“操作 (A)”)可能与 X<>(操作 (R))- 粗略地说,将值分配给 (A) 正在读取的 X 的操作。

[atomics.order]/2 An atomic operation A that performs a release operation on an atomic object M synchronizes with an atomic operation B that performs an acquire operation on M and takes its value from any side effect in the release sequence headed by A.

  1. 这种同步关系可能有助于在 L 的某些修改和赋值 local2 = L 之间建立 happens-before 关系。如果 L 的修改发生在 (R) 之前,那么,由于 (R)( A)(A)L 的读取之前排序,L 的修改发生在这次读取之前L.

  2. 但是 (A) 对赋值 local1 = L 没有任何影响。它既不会导致涉及此分配的数据竞争,也不会帮助防止它们。如果程序是无竞争的,那么它必须采用一些其他机制来确保 L 的修改与这次读取同步(如果它不是无竞争的,那么它会表现出未定义的行为和标准对此没有进一步说明)。


在C++标准的四个角落里谈论“指令重排序”是没有意义的。人们可能会谈论由特定编译器生成的机器指令,或者这些指令由特定 CPU 执行的方式。但从标准的角度来看,这些只是无关紧要的实现细节,只要编译器和 CPU 产生可观察到的行为与标准 (the As-If rule) 描述的抽象机的一种可能执行路径一致即可。

关于c++ - 非原子负载可以在原子获取负载之后重新排序吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38677061/

有关c++ - 非原子负载可以在原子获取负载之后重新排序吗?的更多相关文章

  1. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

    类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

  2. ruby - 使用 Vim Rails,您可以创建一个新的迁移文件并一次性打开它吗? - 2

    使用带有Rails插件的vim,您可以创建一个迁移文件,然后一次性打开该文件吗?textmate也可以这样吗? 最佳答案 你可以使用rails.vim然后做类似的事情::Rgeneratemigratonadd_foo_to_bar插件将打开迁移生成的文件,这正是您想要的。我不能代表textmate。 关于ruby-使用VimRails,您可以创建一个新的迁移文件并一次性打开它吗?,我们在StackOverflow上找到一个类似的问题: https://sta

  3. ruby - 我可以使用 Ruby 从 CSV 中删除列吗? - 2

    查看Ruby的CSV库的文档,我非常确定这是可能且简单的。我只需要使用Ruby删除CSV文件的前三列,但我没有成功运行它。 最佳答案 csv_table=CSV.read(file_path_in,:headers=>true)csv_table.delete("header_name")csv_table.to_csv#=>ThenewCSVinstringformat检查CSV::Table文档:http://ruby-doc.org/stdlib-1.9.2/libdoc/csv/rdoc/CSV/Table.html

  4. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

    我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

  5. ruby - 如何在续集中重新加载表模式? - 2

    鉴于我有以下迁移:Sequel.migrationdoupdoalter_table:usersdoadd_column:is_admin,:default=>falseend#SequelrunsaDESCRIBEtablestatement,whenthemodelisloaded.#Atthispoint,itdoesnotknowthatusershaveais_adminflag.#Soitfails.@user=User.find(:email=>"admin@fancy-startup.example")@user.is_admin=true@user.save!ende

  6. ruby-on-rails - active_admin 目录中的常量警告重新声明 - 2

    我正在使用active_admin,我在Rails3应用程序的应用程序中有一个目录管理,其中包含模型和页面的声明。时不时地我也有一个类,当那个类有一个常量时,就像这样:classFooBAR="bar"end然后,我在每个必须在我的Rails应用程序中重新加载一些代码的请求中收到此警告:/Users/pupeno/helloworld/app/admin/billing.rb:12:warning:alreadyinitializedconstantBAR知道发生了什么以及如何避免这些警告吗? 最佳答案 在纯Ruby中:classA

  7. ruby - 我可以使用 aws-sdk-ruby 在 AWS S3 上使用事务性文件删除/上传吗? - 2

    我发现ActiveRecord::Base.transaction在复杂方法中非常有效。我想知道是否可以在如下事务中从AWSS3上传/删除文件:S3Object.transactiondo#writeintofiles#raiseanexceptionend引发异常后,每个操作都应在S3上回滚。S3Object这可能吗?? 最佳答案 虽然S3API具有批量删除功能,但它不支持事务,因为每个删除操作都可以独立于其他操作成功/失败。该API不提供任何批量上传功能(通过PUT或POST),因此每个上传操作都是通过一个独立的API调用完成的

  8. ruby - 简单获取法拉第超时 - 2

    有没有办法在这个简单的get方法中添加超时选项?我正在使用法拉第3.3。Faraday.get(url)四处寻找,我只能先发起连接后应用超时选项,然后应用超时选项。或者有什么简单的方法?这就是我现在正在做的:conn=Faraday.newresponse=conn.getdo|req|req.urlurlreq.options.timeout=2#2secondsend 最佳答案 试试这个:conn=Faraday.newdo|conn|conn.options.timeout=20endresponse=conn.get(url

  9. ruby - 有人可以帮助解释类创建的 post_initialize 回调吗 (Sandi Metz) - 2

    我正在阅读SandiMetz的POODR,并且遇到了一个我不太了解的编码原则。这是代码:classBicycleattr_reader:size,:chain,:tire_sizedefinitialize(args={})@size=args[:size]||1@chain=args[:chain]||2@tire_size=args[:tire_size]||3post_initialize(args)endendclassMountainBike此代码将为其各自的属性输出1,2,3,4,5。我不明白的是查找方法。当一辆山地自行车被实例化时,因为它没有自己的initialize方法

  10. ruby - 从 Ruby 中的主机名获取 IP 地址 - 2

    我有一个存储主机名的Ruby数组server_names。如果我打印出来,它看起来像这样:["hostname.abc.com","hostname2.abc.com","hostname3.abc.com"]相当标准。我想要做的是获取这些服务器的IP(可能将它们存储在另一个变量中)。看起来IPSocket类可以做到这一点,但我不确定如何使用IPSocket类遍历它。如果它只是尝试像这样打印出IP:server_names.eachdo|name|IPSocket::getaddress(name)pnameend它提示我没有提供服务器名称。这是语法问题还是我没有正确使用类?输出:ge

随机推荐