jjzjj

c# - 32 位环境下 64 位变量的原子增量

coder 2024-05-30 原文

正在为 another question 写一个答案出现了一些有趣的事情,现在我无法理解 Interlocked.Increment(ref long value) 如何在 32 位系统上工作。让我解释一下。

Native InterlockedIncrement64 现在在为 32 位环境编译时不可用,好吧,这是有道理的,因为在 .NET 中你不能按要求对齐内存,它可以从 managed 中调用 然后他们放弃了它。

在 .NET 中,我们可以使用对 64 位变量的引用来调用 Interlocked.Increment(),我们仍然对其对齐方式没有任何约束(例如在结构中,也可以在哪里我们可能会使用 FieldOffsetStructLayout)但是文档没有提到任何限制(AFAIK)。这很神奇,很管用!

Hans Passant 注意到 Interlocked.Increment() 是 JIT 编译器识别的特殊方法,它会发出对 COMInterlocked::ExchangeAdd64() 的调用然后将调用 FastInterlockExchangeAddLong这是 InterlockedExchangeAdd64 的宏与 InterlockedIncrement64 具有相同的限制 .

现在我很困惑。

忘记一秒钟的托管环境并返回本地。为什么 InterlockedIncrement64 不能工作而 InterlockedExchangeAdd64 可以? InterlockedIncrement64 是一个宏,如果内在函数不可用且 InterlockedExchangeAdd64 有效,那么它可以作为对 InterlockedExchangeAdd64 的调用来实现...

让我们回到托管:如何在 32 位系统上实现原子 64 位增量?我想 “这个函数是原子的 相对于调用其他互锁函数 很重要,但我仍然没有看到任何代码(感谢 Hans 指出更深入实现)来做到这一点。当内部函数不可用时,让我们从 WinBase.h 中选择 InterlockedExchangeAdd64 实现:

FORCEINLINE
LONGLONG
InterlockedExchangeAdd64(
    _Inout_ LONGLONG volatile *Addend,
    _In_    LONGLONG Value
    )
{
    LONGLONG Old;

    do {
        Old = *Addend;
    } while (InterlockedCompareExchange64(Addend,
                                          Old + Value,
                                          Old) != Old);

    return Old;
}

如何保证读/写的原子性?

最佳答案

您必须继续跟踪,InterlockedExchangeAdd64() 会将您带到 WinNt.h SDK 头文件。您会在哪里看到它的许多版本,具体取决于目标架构。

这通常会折叠成:

#define InterlockedExchangeAdd64 _InterlockedExchangeAdd64

它将责任推给编译器内部函数,在 vc/include/intrin.h 中声明并由编译器的后端实现。

或者换句话说,不同版本的 CLR 会有不同的实现。多年来,x86、x64、Itanium、ARM、ARM8、PowerPC 从我的脑海中浮现出来,我肯定遗漏了一些在 Apple 使其变得无关紧要之前用于启动 WindowsCE 的东西。对于 x86,这最终由 LOCK CMPXCHNG8B 处理,LOCK CMPXCHNG8B 是一种专用处理器指令,可以处理未对齐的 64 位变量。我没有硬件来查看它在其他 32 位处理器上的样子。

请记住,托管代码的目标体系结构在编译时并未确定。抖动使 MSIL 在运行时适应目标。这与 C++/CLI 项目不太相关,因为如果您使用/clr 而不是/clr:pure 进行编译并且只有 x86 和 x64 可以工作,您通常必须选择一个目标。但是无论如何管道都已到位,因此宏不是很有用。

关于c# - 32 位环境下 64 位变量的原子增量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37561976/

有关c# - 32 位环境下 64 位变量的原子增量的更多相关文章

  1. ruby - 在 64 位 Snow Leopard 上使用 rvm、postgres 9.0、ruby 1.9.2-p136 安装 pg gem 时出现问题 - 2

    我想为Heroku构建一个Rails3应用程序。他们使用Postgres作为他们的数据库,所以我通过MacPorts安装了postgres9.0。现在我需要一个postgresgem并且共识是出于性能原因你想要pggem。但是我对我得到的错误感到非常困惑当我尝试在rvm下通过geminstall安装pg时。我已经非常明确地指定了所有postgres目录的位置可以找到但仍然无法完成安装:$envARCHFLAGS='-archx86_64'geminstallpg--\--with-pg-config=/opt/local/var/db/postgresql90/defaultdb/po

  2. ruby - 什么是填充的 Base64 编码字符串以及如何在 ruby​​ 中生成它们? - 2

    我正在使用的第三方API的文档状态:"[O]urAPIonlyacceptspaddedBase64encodedstrings."什么是“填充的Base64编码字符串”以及如何在Ruby中生成它们。下面的代码是我第一次尝试创建转换为Base64的JSON格式数据。xa=Base64.encode64(a.to_json) 最佳答案 他们说的padding其实就是Base64本身的一部分。它是末尾的“=”和“==”。Base64将3个字节的数据包编码为4个编码字符。所以如果你的输入数据有长度n和n%3=1=>"=="末尾用于填充n%

  3. ruby-on-rails - 如何使用 instance_variable_set 正确设置实例变量? - 2

    我正在查看instance_variable_set的文档并看到给出的示例代码是这样做的:obj.instance_variable_set(:@instnc_var,"valuefortheinstancevariable")然后允许您在类的任何实例方法中以@instnc_var的形式访问该变量。我想知道为什么在@instnc_var之前需要一个冒号:。冒号有什么作用? 最佳答案 我的第一直觉是告诉你不要使用instance_variable_set除非你真的知道你用它做什么。它本质上是一种元编程工具或绕过实例变量可见性的黑客攻击

  4. ruby - 通过 ruby​​ 进程共享变量 - 2

    我正在编写一个gem,我必须在其中fork两个启动两个webrick服务器的进程。我想通过基类的类方法启动这个服务器,因为应该只有这两个服务器在运行,而不是多个。在运行时,我想调用这两个服务器上的一些方法来更改变量。我的问题是,我无法通过基类的类方法访问fork的实例变量。此外,我不能在我的基类中使用线程,因为在幕后我正在使用另一个不是线程安全的库。所以我必须将每个服务器派生到它自己的进程。我用类变量试过了,比如@@server。但是当我试图通过基类访问这个变量时,它是nil。我读到在Ruby中不可能在分支之间共享类变量,对吗?那么,还有其他解决办法吗?我考虑过使用单例,但我不确定这是

  5. ruby-on-rails - 如何在我的 Rails 应用程序 View 中打印 ruby​​ 变量的内容? - 2

    我是一个Rails初学者,但我想从我的RailsView(html.haml文件)中查看Ruby变量的内容。我试图在ruby​​中打印出变量(认为它会在终端中出现),但没有得到任何结果。有什么建议吗?我知道Rails调试器,但更喜欢使用inspect来打印我的变量。 最佳答案 您可以在View中使用puts方法将信息输出到服务器控制台。您应该能够在View中的任何位置使用Haml执行以下操作:-puts@my_variable.inspect 关于ruby-on-rails-如何在我的R

  6. c# - 如何在 ruby​​ 中调用 C# dll? - 2

    如何在ruby​​中调用C#dll? 最佳答案 我能想到几种可能性:为您的DLL编写(或找人编写)一个COM包装器,如果它还没有,则使用Ruby的WIN32OLE库来调用它;看看RubyCLR,其中一位作者是JohnLam,他继续在Microsoft从事IronRuby方面的工作。(估计不会再维护了,可能不支持.Net2.0以上的版本);正如其他地方已经提到的,看看使用IronRuby,如果这是您的技术选择。有一个主题是here.请注意,最后一篇文章实际上来自JohnLam(看起来像是2009年3月),他似乎很自在地断言RubyCL

  7. ruby-on-rails - 在 Rails 开发环境中为 .ogv 文件设置 Mime 类型 - 2

    我正在玩HTML5视频并且在ERB中有以下片段:mp4视频从在我的开发环境中运行的服务器很好地流式传输到chrome。然而firefox显示带有海报图像的视频播放器,但带有一个大X。问题似乎是mongrel不确定ogv扩展的mime类型,并且只返回text/plain,如curl所示:$curl-Ihttp://0.0.0.0:3000/pr6.ogvHTTP/1.1200OKConnection:closeDate:Mon,19Apr201012:33:50GMTLast-Modified:Sun,18Apr201012:46:07GMTContent-Type:text/plain

  8. C# 到 Ruby sha1 base64 编码 - 2

    我正在尝试在Ruby中复制Convert.ToBase64String()行为。这是我的C#代码:varsha1=newSHA1CryptoServiceProvider();varpasswordBytes=Encoding.UTF8.GetBytes("password");varpasswordHash=sha1.ComputeHash(passwordBytes);returnConvert.ToBase64String(passwordHash);//returns"W6ph5Mm5Pz8GgiULbPgzG37mj9g="当我在Ruby中尝试同样的事情时,我得到了相同sha

  9. ruby-on-rails - 使用 ruby​​ 将多个实例变量转换为散列的更好方法? - 2

    我收到格式为的回复#我需要将其转换为哈希值(针对活跃商家)。目前我正在遍历变量并执行此操作:response.instance_variables.eachdo|r|my_hash.merge!(r.to_s.delete("@").intern=>response.instance_eval(r.to_s.delete("@")))end这有效,它将生成{:first="charlie",:last=>"kelly"},但它似乎有点hacky和不稳定。有更好的方法吗?编辑:我刚刚意识到我可以使用instance_variable_get作为该等式的第二部分,但这仍然是主要问题。

  10. ruby - Rack:如何将 URL 存储为变量? - 2

    我正在编写一个简单的静态Rack应用程序。查看下面的config.ru代码:useRack::Static,:urls=>["/elements","/img","/pages","/users","/css","/js"],:root=>"archive"map'/'dorunProc.new{|env|[200,{'Content-Type'=>'text/html','Cache-Control'=>'public,max-age=6400'},File.open('archive/splash.html',File::RDONLY)]}endmap'/pages/search.

随机推荐