【发布时间】:2012-08-10 21:06:52
【问题描述】:
private InstrumentInfo[] instrumentInfos = new InstrumentInfo[Constants.MAX_INSTRUMENTS_NUMBER_IN_SYSTEM];
public void SetInstrumentInfo(Instrument instrument, InstrumentInfo info)
{
if (instrument == null || info == null)
{
return;
}
instrumentInfos[instrument.Id] = info; // need to make it visible to other threads!
}
public InstrumentInfo GetInstrumentInfo(Instrument instrument)
{
return instrumentInfos[instrument.Id]; // need to obtain fresh value!
}
SetInstrumentInfo 和 GetInstrumentInfo 是从不同的线程调用的。
InstrumentInfo 是不可变类。
拨打GetInstrumentInfo 时,我能保证获得最新的副本吗?恐怕我会收到“缓存”副本。我应该添加某种同步吗?
将instrumentInfos 声明为volatile 没有帮助,因为我需要将数组项声明为volatile,而不是数组本身。
我的代码有问题吗?如果有,如何解决?
UPD1:
我需要我的代码在现实生活中工作,而不是符合所有规范!因此,如果我的代码在现实生活中有效,但在某些环境下的某些计算机上“理论上”不能工作 - 没关系!
- 我需要我的代码在使用最新 .NET Framework 的 Windows 下在现代 X64 服务器(当前为 2 个处理器 HP DL360p Gen8)上工作。
- 我不需要在奇怪的计算机或 Mono 或其他任何东西下处理我的代码
- 我不想引入延迟,因为这是 HFT 软件。因此,由于“Microsoft 的实现使用强大的内存模型进行写入。这意味着写入被视为易失性”,我可能不需要添加额外的
Thread.MemoryBarrier,这只会增加延迟。我认为我们可以相信微软将在未来的版本中继续使用“强内存模型”。至少微软不太可能改变内存模型。所以我们假设它不会。
UPD2:
最近的建议是使用Thread.MemoryBarrier();。现在我不明白我必须将它插入的确切位置,才能使我的程序在 standard 配置(x64、Windows、Microsoft .NET 4.0)上运行。请记住,我不想插入“只是为了在 IA64 或 .NET 10.0 上启动您的程序”的行。速度对我来说比便携性更重要。然而,如何更新我的代码以便它可以在任何计算机上运行也会很有趣。
UPD3
.NET 4.5 解决方案:
public void SetInstrumentInfo(Instrument instrument, InstrumentInfo info)
{
if (instrument == null || info == null)
{
return;
}
Volatile.Write(ref instrumentInfos[instrument.Id], info);
}
public InstrumentInfo GetInstrumentInfo(Instrument instrument)
{
InstrumentInfo result = Volatile.Read(ref instrumentInfos[instrument.Id]);
return result;
}
【问题讨论】:
-
@svick 所以我必须使用
Thread.MemoryBarrier();?上面写的代码行不通? -
是的,这是一种选择。但如果可以的话,我更喜欢使用
Thread.Volatile(Read|Write)(或Volatile.(Read|Write))。是的,我认为你的代码不能工作,因为它可以读取过时的数据。 -
更糟。它在大多数情况下都会起作用,但有可能不起作用;取决于它在哪台机器上运行的潜力。不工作的代码比那更容易修复。
-
@JonHanna 这个代码可以在哪台机器上运行?如果它可以在 x64 机器上运行,那么我宁愿不介绍任何东西。因为我不需要延迟,因为它是 HFT 软件的一部分。
-
@Xantix 即 reference 分配保证在 C# 规范和 CLi 中都是线程安全的。
标签: c# multithreading synchronization volatile