您的位置:知识库 » .NET技术

再说 lock-free 编程

作者: Angel Lucifer  来源: 博客园  发布时间: 2009-04-09 10:00  阅读: 12500 次  推荐: 0   原文链接   [收藏]  
摘要:这篇文章阐述如何再使用lock-free 技术的时候,它的一些负面影响。
[1] 说明一下lock-free编程
[2] 在实例中讲解lock-free技术的影响

  lock-free  编程实在让人又爱又恨。博主以前曾经写过几篇关于 lock-free 编程的文章。比如关于无锁编程并发数据结构:迷人的原子。如果想更加深入的了解和实践 lock-free 编程,可以参考CLR 2.0 Memory Model并发数据结构:Stack。这篇文章并不打算继续阐述如何使用 lock-free 技术,而是谈一下它的负面影响。从而让大家对 lock-free 有个更加全面的认识。

  说到 lock-free 编程,现实中经常使用 CAS 原语。CAS 是英文 Compare and Swap 的简写。在 Windows 和 .NET 平台,由于历史原因,它被写做 Interlocked API。原子操作在 x86 架构 CPU 对应的汇编指令有 XCHG、CMPXCHG、INC 等,当然还得加上 LOCK 作为前缀(更多信息请看 并发数据结构:迷人的原子)。

  CAS 原语在轻度和中度争用情况下确实可以大幅度提高程序性能。但凡事有利必有弊,CAS 原语极度扼杀了程序的可伸缩性(其他缺点请看关于无锁编程)。各位看官可能觉得这种观点有点偏激,但事实如此。请容博主细细道来:

  • CAS 的原子性完全取决于硬件实现。大多数 Intel 和 AMD 的 CPU 采用了一种叫做 MOSEI 缓存一致性协议来管理缓存。这种架构下,处理器缓存内 CAS 操作相对成本低廉。但一旦资源争用,就会引起缓存失效和总线占用。缓存越失效,总线越被占用,完成 CAS 操作也越被延迟。缓存争用是程序可伸缩性杀手。当然对于非 CAS 内存操作来说也是如此,但 CAS 情况更加槽糕。
  • CAS 操作要比普通内存操作花费更多 CPU 周期。这归功于缓存分级的额外负担、刷新写缓冲区与穿越内存栅栏限制和需求以及编译器对 CAS 操作优化的能力。
  • CAS 经常被用在优化并行操作上。这意味着 CAS 操作失败将导致重新尝试某些指令(典型的回滚操作)。即便没有任何争用,它也会做一些无用功。不论成功或失败都会增加争用的风险。

  大多数 CAS 操作发生在锁进入和退出时。尽管锁可由单一 CAS 操作构建,但 .NET CLR Monitor 类却使用了两个(一个在 Enter 方法,另一个在 Exit 方法)。lock-free 算法也经常使用 CAS 原语来代替使用锁机制。但是由于内存重组,这样的算法也常常需要显式的栅栏,即便使用了 CAS 指令。锁机制非常邪恶,但大多数合格的开发人员都知道让锁持有尽量少的时间。因此,虽然锁机制让人非常讨厌,且影响性能。但相对于大量,频繁的 CAS 操作而言,它却并不影响程序的可伸缩性。

  举个很简单的例子,增加计数 100,000,000 次。要做到这样,有几种方式。如果仅运行在单核单处理器上,我们可以使用普通的内存操作:

static volatile int counter = 0;
static void BaselineCounter()
{
    for (int i = 0; i < Count; i++)
    {
        counter++;
    }
}

  很明显,上述代码示例不是线程安全的,但给计数器提供了一个很好的时间基准。下面我们使用 LOCK INC 来作为线程安全的第一种方式:

static volatile int counter = 0;
static void LockIncCounter()
{
    for (int i = 0; i < Count; i++)
    {
        Interlocked.Increment(ref counter);
    }
}

 

  现在代码示例线程安全了。我们还可以采取另外一种方式来保证线程安全。如果需要执行一些验证(比如内存溢出保护),我们通常会使用这种方式。就是使用 CMPXCHG(即 CAS):

static volatile int counter = 0;
static void CASCounter()
{
    for (int i = 0; i < Count; i++)
    {
        int oldValue;
        do
        {
            oldValue = counter;
        }
        while (Interlocked.CompareExchange(ref counter, oldValue + 1, oldValue) != oldValue);
    }
}

[第1页][第2页]
0
0
标签:CLR

.NET技术热门文章

    .NET技术最新文章

      最新新闻

        热门新闻