关于线程同步的一些问题

时间:2010-11-18 13:29:54

标签: .net multithreading

我有一些问题需要澄清。

  1. 易失性读取确保您阅读 变量的最新值。可以 意味着它强制所有的CPU 刷新他们的缓存值 变量?只有那个变量或全部? 因此,如果它将强制所有CPU 刷新缓存写入并获取最新信息 来自主内存的版本,这是一个 记忆障碍?

  2. 易失性写入确保您写入 main中变量的值 记忆。这是否意味着它无效 所有缓存的值 所有CPU中都有变量吗?

  3. 你在使用内存屏障时 你使用关键字volatile?

  4. Interloked表演了一个 读取/修改/写入原子 操作。联锁是否确保 你就是这样的人 递增最新版本的 变量和其他CPU会看到 这个改变?我想是因为它是 应该使用记忆障碍, 但我不确定。我们可以说 那个Interloked正在做一个 VolatileRead /修改/ VolatileWrite 原子?

  5. 使用内存屏障时,确实如此 它会影响所有变量 CPUS,还是周围的CPUS?

  6. 锁定很昂贵,因为它 导致两个记忆障碍和一个 如果线程有“上下文切换” 等待,但那是什么 联锁的优势?只为了 避免“上下文切换”?

  7. 有什么优惠 ReaderWriterLockSlim和 递归性?我没有说过 问题是什么。

  8. 正如你所看到的,我现在心里一团糟。

    提前致谢。

2 个答案:

答案 0 :(得分:7)

在回答您的问题之前,我应该指出,内存障碍不仅仅影响CPU。应用程序运行时,实际上有两种内存模型在运行。一个是硬件级别,另一个是软件级别。作为开发人员,您必须编写两者中不同元素的最弱组合。使用CLR和x86架构,这通常意味着CLR更重要,因为x86架构实际上具有相当强大的内存模型。换句话说,volatile关键字和其他内存屏障机制也将影响JIT如何生成代码。

  

1.易失性读取确保您读取变量的最新值。可以   意味着它强制所有的CPU   刷新他们的缓存值   变量?只有那个变量或全部?   所以如果它会强制所有CPU刷新   缓存写入并获取最新版本   从主内存来看,这是一个记忆   屏障?

首先,从技术上讲,易失性读取不能确保您读取变量的最新值。它实际上意味着在volatile之前不会发生其他读或写。但是,效果是读取必须来自主存储器,如果之前是另一个易失性读取。其次,不,易失性读取对其他写入没有影响,因此它不会强制所有CPU刷新其写入缓存。第三,是的,挥发性操作被认为是一种记忆障碍。

  

2.易失性写入确保您为主存储器中的变量写入值。   这是否意味着它使所有的都无效   总计该变量的缓存值   的CPU?

与易失性读取类似,易失性写入在技术上与订购有关。它确保在volatile之后不会发生其他读或写。这并不意味着立即提交有问题的写入。它只影响执行该线程的CPU。有趣的是,x86架构实际上将所有写入视为易失性。但是,CLR没有(至少是ECMA规范)。这就是为什么你仍然需要在写入时使用volatile操作。这是从硬件和软件级别对最弱的内存模型元素进行编码的一个示例。

  

3.使用关键字volatile?

时是否使用了内存屏障?

是。有两种类型的记忆障碍。全围栏和半围栏。半栅栏可以保证获取语义(易失性读取)或释放语义(易失性写入),但不能同时获得两者。完整的围栏(例如通过Thread.MemoryBarrier)保护两者。

  

4.Interloked在原子中执行读/修改/写入   操作。联锁是否确保   你是增量的例子   最新版本的变量和   其他CPU会看到这种变化吗?一世   这么认为是因为它应该使用   记忆障碍,但我不确定。所以   我们可以说Interloked正在做   一个VolatileRead / modify / VolatileWrite   原子?

是的。值得一提的是,可以使用CAS操作实现互锁增量和减量操作。在.NET中,您将在循环中使用Interlocked.CompareExchange方法,直到操作成功。我敢打赌,Interlocked.IncrementInterlocked.Decrement方法虽然使用了本地CPU指令,但我准备对此做错。

  

5.当您使用内存屏障时,它是否会影响所有变量   CPUS,还是周围的CPUS?

它将影响所有内存访问,但仅限于执行该线程的CPU。

  

6.锁定是昂贵的,因为它会导致两个内存屏障和a   如果线程必须“上下文切换”   等等,但那有什么好处   联锁?只是为了避免   “上下文切换”?

基本上是的。线程永远不会阻塞互锁操作。

  

7.与ReaderWriterLockSlim和递归有什么关系?   我没有说明问题是什么。

如果没有先释放它,则无法在同一个线程上获取锁定两次。关于Joe Duffy's blog的更多信息。

答案 1 :(得分:1)

锁的一个问题是,任何获取锁的线程都必须承担其他线程可能在任意长度内持有锁的风险。保证Threading.Interlocked.CompareExchange调用几乎立即返回(无论是否成功);除非在故意重大争用的情况下, short CompareExchange螺旋锁也将快速返回。如果一个线程获得了一个锁,然后在它释放之前关闭并执行其他操作,那么其他线程将必须等待其他事情完成才能获得锁定。 CompareExchange螺旋锁没有这样的危险。除非其他线程自己主动点击自旋锁,否则自旋锁将很快完成。