草庐IT

c++ - 比较和交换 : synchronizing via different data sizes

coder 2023-06-03 原文

使用 GCC 内置的 C 原子原语,我们可以使用 __atomic_compare_exchange 执行原子 CAS 操作。

与 C++11 的 std::atomic 类型不同,GCC C 原子原语在常规的非原子整数类型上运行,包括 cmpxchg16b 平台上的 128 位整数> 支持。 (C++ 标准的 future 版本可能支持与 std::atomic_view 类模板类似的功能。)

这让我产生疑问:

如果对较大数据大小的原子 CAS 操作观察到由对同一内存位置的原子操作发生的变化,但使用较小的数据大小会发生什么?

例如,假设我们有:

struct uint128_type {
  uint64_t x;
  uint64_t y;
} __attribute__ ((aligned (16)));

假设我们有一个 uint128_type 类型的共享变量,比如:

uint128_type Foo;

现在,假设线程 A:

    Foo expected = { 0, 0 };
    Foo desired = { 100, 100 };
    int result = __atomic_compare_exchange(
        &Foo, 
        &expected, 
        &desired, 
        0, 
        __ATOMIC_SEQ_CST
    );

线程 B 会这样做:

    uint64_t expected = 0;
    uint64_t desired = 500;
    int result = __atomic_compare_exchange(
        &Foo.x, 
        &expected, 
        &desired, 
        0, 
        __ATOMIC_SEQ_CST
    );

如果线程 A 的 16 字节 CAS 发生在线程 B 的 8 字节 CAS 之前会发生什么(反之亦然)? CAS 是否正常失败?这甚至是定义的行为吗?这是否可能在支持 16b CAS 的 x86_64 等典型架构上“做正确的事”?

编辑:要清楚,因为它似乎会引起混淆,我询问上述行为是否由 C++ 标准定义。显然,所有 __atomic_* 函数都是 GCC 扩展。 (但是,如果 std::atomic_view 变得标准化, future 的 C++ 标准可能必须定义这类事情。)我更一般地询问典型现代硬件上原子操作的语义。举个例子,如果 x86_64 代码有 2 个线程对同一个内存地址执行原子操作,但是一个线程使用 CMPXCHG8b 而另一个使用 CMPXCHG16b,那么一个线程执行原子操作对单个词进行 CAS,而对双词进行原子 CAS,这些操作的语义是如何定义的?更具体地说,CMPXCHG16b 是否会因为先前的 CMPXCHG8b 观察到数据与预期值发生变异而失败?

换言之,使用两种不同数据大小(但起始内存地址相同)的两种不同 CAS 操作能否安全地用于线程间同步?

最佳答案

一个或另一个先发生,每个操作都根据自己的语义进行。

在 x86 CPU 上,这两个操作都需要锁定在整个操作过程中保持的同一高速缓存行。因此,无论谁先获得该锁,都不会看到第二次操作的任何效果,而无论谁第二次获得该锁,都会看到第一次操作的所有效果。两种操作的语义都将得到充分尊重。

其他硬件可能会以其他方式达到这个结果,但如果它没有达到这个结果,它就会被破坏,除非它指定它有限制。

关于c++ - 比较和交换 : synchronizing via different data sizes,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36658597/

有关c++ - 比较和交换 : synchronizing via different data sizes的更多相关文章

  1. ruby - Ruby 的 Hash 在比较键时使用哪种相等性测试? - 2

    我有一个围绕一些对象的包装类,我想将这些对象用作散列中的键。包装对象和解包装对象应映射到相同的键。一个简单的例子是这样的:classAattr_reader:xdefinitialize(inner)@inner=innerenddefx;@inner.x;enddef==(other)@inner.x==other.xendenda=A.new(o)#oisjustanyobjectthatallowso.xb=A.new(o)h={a=>5}ph[a]#5ph[b]#nil,shouldbe5ph[o]#nil,shouldbe5我试过==、===、eq?并散列所有无济于事。

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

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

  3. ruby - 使用 `+=` 和 `send` 方法 - 2

    如何将send与+=一起使用?a=20;a.send"+=",10undefinedmethod`+='for20:Fixnuma=20;a+=10=>30 最佳答案 恐怕你不能。+=不是方法,而是语法糖。参见http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_expressions.html它说Incommonwithmanyotherlanguages,Rubyhasasyntacticshortcut:a=a+2maybewrittenasa+=2.你能做的最好的事情是:

  4. ruby - 如何计算 Liquid 中的变量 +1 - 2

    我对如何计算通过{%assignvar=0%}赋值的变量加一完全感到困惑。这应该是最简单的任务。到目前为止,这是我尝试过的:{%assignamount=0%}{%forvariantinproduct.variants%}{%assignamount=amount+1%}{%endfor%}Amount:{{amount}}结果总是0。也许我忽略了一些明显的东西。也许有更好的方法。我想要存档的只是获取运行的迭代次数。 最佳答案 因为{{incrementamount}}将输出您的变量值并且不会影响{%assign%}定义的变量,我

  5. ruby - 是否有用于复杂比较的漂亮语法? - 2

    方法应返回-1,0或1分别表示“小于”、“等于”和“大于”。对于某些类型的可排序对象,通常将排序顺序基于多个属性。以下是可行的,但我认为它看起来很笨拙:classLeagueStatsattr_accessor:points,:goal_diffdefinitializepts,gd@points=pts@goal_diff=gdenddefothercompare_pts=pointsother.pointsreturncompare_ptsunlesscompare_pts==0goal_diffother.goal_diffendend尝试一下:[LeagueStats.new(

  6. arrays - Ruby 数组 += vs 推送 - 2

    我有一个数组数组,想将元素附加到子数组。+=做我想做的,但我想了解为什么push不做。我期望的行为(并与+=一起工作):b=Array.new(3,[])b[0]+=["apple"]b[1]+=["orange"]b[2]+=["frog"]b=>[["苹果"],["橙子"],["Frog"]]通过推送,我将推送的元素附加到每个子数组(为什么?):a=Array.new(3,[])a[0].push("apple")a[1].push("orange")a[2].push("frog")a=>[[“苹果”、“橙子”、“Frog”]、[“苹果”、“橙子”、“Frog”]、[“苹果”、“

  7. += 的 Ruby 方法 - 2

    有没有办法让Ruby能够做这样的事情?classPlane@moved=0@x=0defx+=(v)#thisiserror@x+=v@moved+=1enddefto_s"moved#{@moved}times,currentxis#{@x}"endendplane=Plane.newplane.x+=5plane.x+=10putsplane.to_s#moved2times,currentxis15 最佳答案 您不能在Ruby中覆盖复合赋值运算符。任务在内部处理。您应该覆盖+,而不是+=。plane.a+=b与plane.a=

  8. ruby - 尝试比较两个文本文件,并根据信息创建第三个 - 2

    我有两个文本文件,master.txt和926.txt。如果926.txt中有一行不在master.txt中,我想写入一个新文件notinbook.txt。我写了我能想到的最好的东西,但考虑到我是一个糟糕的/新手程序员,它失败了。这是我的东西g=File.new("notinbook.txt","w")File.open("926.txt","r")do|f|while(line=f.gets)x=line.chompifFile.open("master.txt","w")do|h|endwhile(line=h.gets)ifline.chomp!=xputslineendende

  9. ruby - Sinatra + Heroku + Datamapper 使用 dm-sqlite-adapter 部署问题 - 2

    出于某种原因,heroku尝试要求dm-sqlite-adapter,即使它应该在这里使用Postgres。请注意,这发生在我打开任何URL时-而不是在gitpush本身期间。我构建了一个默认的Facebook应用程序。gem文件:source:gemcuttergem"foreman"gem"sinatra"gem"mogli"gem"json"gem"httparty"gem"thin"gem"data_mapper"gem"heroku"group:productiondogem"pg"gem"dm-postgres-adapter"endgroup:development,:t

  10. ruby-on-rails - 我如何比较 'Bcrypt' Gem解密的密码和加密的密码 - 2

    我正在尝试对某些帖子的评论使用简单的身份验证。用户使用即时ID和密码输入评论我使用“bcrypt”gem将密码存储在数据库中。在comments_controller.rb中像这样@comment=Comment.new(comment_params)bcrypted_pwd=BCrypt::Password.create(@comment.user_pwd)@comment.user_pwd=bcrypted_pwd当用户想要删除他们的评论时,我使用data-confirm-modalgem来确认数据在这部分,我必须解密用户输入的密码以与数据库中的加密密码进行比较我怎样才能解密密码,

随机推荐