保证多处理器系统上的多个线程始终可以看到变量的最新值

jav*_*red 25 .net c# multithreading

我正在使用这样的配置:

  • .NET framework 4.5
  • Windows Server 2008 R2
  • HP DL360p Gen8(2*Xeon E5-2640,x64)

我的程序中有这样的字段:

protected int HedgeVolume;
Run Code Online (Sandbox Code Playgroud)

我从几个线程访问此字段.我假设因为我有多处理器系统,所以这个线程可能在不同的处理器上执行.

我该怎么做才能保证在任何时候我使用这个字段的最新值是"读"?并确保当我"写"值时,它立即可用于所有其他线程?

我该怎么办?

  • 只是按原样离开现场.
  • 宣布它 volatile
  • 使用Interlocked类来访问该字段
  • 使用.NET 4.5 Volatile.Read,Volatile.Write访问该字段的方法
  • 使用 lock

我只需要最简单的方法让我的程序在这个配置上工作我不需要我的程序在另一台计算机或服务器或操作系统上工作.此外,我想要最小的延迟,所以我正在寻找最快的解决方案,它将始终适用于此标准配置(多处理器intel x64,.net 4.5).

Lig*_*ker 7

您的问题缺少一个关键要素......该领域数据的完整性有多重要?

volatile为您提供性能,但如果某个线程当前正在对该字段进行更改,那么在完成之前您将无法获取该数据,因此您可能会访问过期信息,并可能覆盖另一个线程当前正在执行的更改.如果数据是敏感的,您可能会收到很难跟踪的错误.但是,如果您正在进行非常快速的更新,请在不读取数据的情况下覆盖该值,并且不要忘记曾经有一段时间(过几毫秒)数据,请继续进行更新.

lock保证一次只有一个线程可以访问该字段.您只能将其放在编写字段的方法上,并单独保留读取方法.缺点是,它很慢,并且可能在另一个执行其任务时阻塞线程.但是,您确定您的数据保持有效.

Interlock存在以保护自己免受调度程序上下文切换的影响.我的看法?除非您确切知道为什么要使用它以及如何使用它,否则不要使用它.它提供了选择,但是有很多选择会带来很大的问题.它会在更新变量时阻止上下文切换.它可能不会按照您的想法执行操作,也不会阻止并行线程同时执行其任务.


M A*_*ifi 5

您想使用Volatile.Read().

当您在 x86 上运行时,所有在 C# 中的写入都等效于Volatile.Write(),您只需将其用于 Itanium。

Volatile.Read() 将确保您获得最新的副本,无论最后是哪个线程编写的。

这里有一篇很棒的文章,C# Memory Model Explained

它的摘要包括,

在某些处理器上,编译器不仅必须避免对 volatile 读写进行某些优化,还必须使用特殊指令。在多核机器上,不同的内核有不同的缓存。默认情况下,处理器可能不会费心保持这些缓存的一致性,并且可能需要特殊指令来刷新和刷新缓存。

希望这是显而易见的,除了需要volatile阻止编译器优化它之外,还有处理器。

但是,在 C# 中,所有写入都是 volatile(与 Java 中所说的不同),无论您写入的是 volatile 字段还是非 volatile 字段。所以,上述情况在 C# 中实际上从未发生过。易失性写入更新线程的缓存,然后将整个缓存刷新到主内存。

你不需要Volatile.Write()。更权威的来源,Joe Duffy CLR Memory Model。但是,您可能需要它来阻止编译器对其重新排序。

由于所有 C# 写入都是易失性的,因此您可以将所有写入视为直接进入主内存。常规的非易失性读取可以从线程的缓存中读取值,而不是从主

你需要 Volatile.Read()