多处理器系统中volatile关键字的成本是多少?

时间:2009-06-16 16:59:05

标签: c# multithreading volatile

我们遇到了性能问题,一个潜在的罪魁祸首是集中使用易失性单例。具体代码的格式为

class foo {
  static volatile instance;
  static object l = new object();

  public static foo Instance {
    if (instance == null)
      lock(l) {
        if (instance == null)
          instance = new foo();
      }

    return foo();
  }
}

这是在一个8路的盒子上运行,我们看到上下文切换到每秒500,000的音调。典型的系统资源很好 - 25%cpu util,25%内存util,低IO,无分页等。

使用volatile字段是否会导致内存屏障或任何类型的cpu缓存重新加载?或者它只是每次只追踪主存储器,仅用于该字段?

6 个答案:

答案 0 :(得分:4)

lock确实会导致内存障碍,因此如果您总是在锁中访问实例,则不需要使用volatile。

根据this site

  

C#volatile关键字实现了获取和释放语义,这意味着读取时读取内存屏障,写入时写入内存屏障。

答案 1 :(得分:3)

volatile不会做的一件事是导致上下文切换。如果您每秒看到500,000个上下文切换,则意味着您的线程阻塞了某些内容,而volatile是而不是的罪魁祸首。

答案 2 :(得分:1)

可悲的是,单身人士对所有事情都采取了不好的说法:)

这不是我的专业领域,但据我所知,除了编译器/运行时没有重新排序读/写(到变量)以进行优化之外,没有什么特别的易失性。

编辑:我的立场得到了纠正。 volatile不仅会引入内存障碍,而且发生的事情(以及顺便提一下,性能)在很大程度上取决于所涉及的特定CPU。 见http://dotnetframeworkplanet.blogspot.com/2008/11/volatile-field-and-memory-barrier-look.html

这就是你仍然需要锁定的原因。

可能已经/可能尚未回答的问题:

  1. 你的单身实例究竟在做什么?也许实例代码需要重构......
  2. 正在运行的进程的线程数是多少?如果您的线程数异常高,8路盒子将无法帮助您。
  3. 如果高于预期,为什么?
  4. 系统上还运行了什么?
  5. 性能问题是否一致?

答案 3 :(得分:0)

在你的例子中,volatile不应该是任何“减速”的主题。 然而,lock()可能涉及到内核的大量往返,特别是如果存在大量争用锁定的话。

在这种情况下,确实没有必要锁定你的单身人士 做

class Foo {
  static Foo instance = new Foo();
  public static Foo FooInstance() {
    return instance ;
  }
}

当然,如果在许多不同的线程中使用'instance',你仍然必须锁定()改变Foo的任何东西,除非Foo的所有方法/属性都是只读的。 e.g。

 class Foo {
      static Foo instance = new Foo();
      object l = new object();
      int doesntChange = 42;
      int canChange = 123;
      public static Foo FooInstance() {
        return instance ;
      }
      public void Update(int newVal) {
         lock(l) { // you'll get a lot of trouble without this lock if several threads accesses the same FOO. Atleast if they later on read that variable 
            canChange = newVal;
         }

      public int GetFixedVal() {
         return doesntChange; //no need for a lock. the doesntChange is effectivly read only
      }
    }

答案 4 :(得分:0)

实际上不需要为单例使用volatile,因为你只需要设置一次 - 并锁定代码设置它。有关详细信息,请参阅Jon Skeet's article on singletons

答案 5 :(得分:0)

简短的回答是,是的,它会创建一个内存屏障(刷新所有内容并转到主内存,而不仅仅是单个变量),但不会导致上下文切换。

此外,正如其他人所说,我不认为这里有必要的挥发性。