结构撕裂是Memory的一个问题 ?

问题描述 投票:0回答:1

首先要做的事情:

  • 我知道Span<T>Memory<T>是什么
  • 我知道为什么Span<T>必须只驻留在Stack上
  • 我(从概念上)知道什么是结构撕裂

我还不清楚:对于Memory<T>来说,结构撕裂是不是一个问题?据我所知,基本上每个大于WORD大小的类型都会受到影响。更进一步,当这种类型可用于多线程读写器场景时,它可能导致竞争条件,如下面的链接所述。

为了达到这一点:当使用this example代替Memory<T>时,Span<T>是否也会提出可能不一致的internal class Buffer { Memory<byte> _memory = new byte[1024]; public void Resize(int newSize) { _memory = new byte[newSize]; // Will this update atomically? } public byte this[int index] => _memory.Span[index]; // Won't this also possibly see partial update? } 对象的问题:

implementation of CoreFX

根据Memory<T>Span<T>还按顺序列出了一个(托管对象)引用,它的长度和索引。与Memory<T>的区别在哪里,我错过了,这使得Memory<T>适合那些场景?

c# .net memory-management .net-core tearing
1个回答
2
投票

通过阅读Memory<T>.Pin()中的评论,看起来它绝对可以撕裂。

然而,似乎有两个地方真正重要:Memory<T>.SpanMemory<T>.Span

需要注意的重要一点是(据我可以解决)我们不关心以某种方式撕裂,这意味着我们仍然指向我们引用的对象中的某个位置 - 尽管我们的调用者可能会得到一些奇怪的数据它没有预料到,这是安全的,因为他们不会得到AccessViolationException。由于对字段进行了不同步的线程访问,它们只会产生竞争条件,从而产生意外结果。


Span<T>Memory<T>获得了this comment。它有Memory<T>

如果Memory或ReadOnlyMemory实例被撕裂,则此属性getter具有未定义的行为。我们尝试检测这种情况并抛出一个异常,但是撕裂的结构可能在我们看来是有效的,并且我们将返回一个不需要的跨度。与原始内存实例相比,这样的跨度始终保证至少是入站,因此使用跨度将不会AV过程。

所以,我们绝对可以撕裂Span<T>,然后尝试从中创建一个Memory<T>。在这种情况下,如果Memory<T>以这样的方式撕裂,它现在引用了Span<T>引用的对象之外的某些内存,那么代码中会检查抛出异常。

如果它仍然以某种方式撕裂它仍然引用原始对象中的某个地方,那就没关系 - 我们的调用者可能没有读取它期望读取的东西,但至少他们不会得到AccessViolationException,这是什么我们试图避免。

请注意,Memory<T>无法实现相同的检查(即使它想要)。 Span<T>保持对对象,起始偏移和长度的引用。 Memory<T>.Pin()只保留对象内部的一些内存地址和长度的引用。


unsafethis comment方法,有unsafe

如果结构被撕裂,下面的逻辑可能会导致AV。这是好的,因为调用者期望使用原始指针,我们不需要将其保持为与其他基于Span的API一样安全。

同样,我们可以撕裂我们不再引用我们所指的对象内部的某个地方。然而,这种方法是qazxswpoi,我们不在乎。

© www.soinside.com 2019 - 2024. All rights reserved.