假设我有一个由 100 个字节组成的结构。我对以下代码有什么保证?

m_myLargeStruct = someValue; // copying 100 bytes
Thread.MemoryBarrier();

// Executed by another thread, after "Thread.MemoryBarrier" was called by the first thread
Console.WriteLine(m_myLargeStruct.ToString());

内存模型是否保证在放置内存屏障后完成 100 字节的复制?或者内存屏障仅适用于处理器架构大小的类型?(32 位为 4 个字节,64 位为 8 个字节)。
这就是为什么 易挥发的 关键字仅适用于原始类型?(如果我将 8 字节成员声明为易失性,这意味着将使用互锁指令来更改其值?[因为在 32 位机器上大于 4 字节的类型不能保证原子性])。

我希望我说得足够清楚..:)
谢谢

有帮助吗?

解决方案

显然,答案是,或者说,你不知道什么保证。没有什么能够阻止所述操作系统从换出正在启动该打印出100字节结构的线程之前写入100字节结构的线程。

当你想通过坐标的标志或一些其它原子值对数据的访问的存储器屏障被使用。我不知道到底是什么你正在尝试做的,所以我不能给你,你应该怎么做才好吃的示例代码。

其他提示

除非读取线程也有内存屏障,否则我不会 思考 它会对你有很大帮助。

就我个人而言,我会回避:

  • 这么大的结构
  • 深入内存模型编写无锁代码

...除非你有非常重要的理由这样做。它是 极大地 很难对可变数据进行无锁编码;我相信即使是专家也会遇到困难。我通常发现“为访问数据的每个块锁定”方法更容易正确,并且在 99% 的情况下性能都很好。

我相信 Microsoft 的 PFX 团队能够正确进行无锁编码,并且他们为我提供了使用他们的代码相对轻松地编写我自己的无锁程序的方法。我不相信自己能把这种事情做好。如果我需要显式地使用内存屏障,那可能意味着我太努力了。

您需要在第二线程中的另一个存储器屏障,之前的WriteLine。 (如果系统提供非对称存储器的障碍,它足以执行分配之后的推出屏障和WriteLine之前采集屏障)。

数据大小并不重要。

您需要在这两个地方/线程内存屏障,当然,你需要某种两者之间的同步,因此第二个的线程的屏障之前没有得到“跑”的第一个线程的。

具体而言,写入线程需要一个“释放”存储器屏障,并且读取线程需要一个“获取”存储器屏障(如果底层平台支持单独的屏障语义)。

除非你问出来的学术好奇心或者你正在写自己的框架,你应该只使用一个同步对象从库/框架/平台。试图让这一切的东西正确的是棘手的,并且它在提供的同步对象已经完成了。

好了,首先你不应该有一个结构是那么大。除非你非常小心你如何使用结构,这将是比使用一个类慢。此外,它是反直觉结构的值语义。

这就是说,存储器屏障将保证该结构被复制。优化不会移动穿过屏障的任何指令。

挥发性关键字是有点不同。它保证对变量进行任何操作被优化掉,它也保证顺序的内存访问。但是,对于无法访问原子的数据类型,它是线程的目的,你仍然可以读取一个新的价值的一半,另一半的旧值的大多无用。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top