【问题标题】:Interlocked class联锁类
【发布时间】:2010-10-27 13:16:50
【问题描述】:

到目前为止,我使用 lock(object) 构造来访问共享变量。 在阅读了有关 Interlocked 的 msdn 文章后

Increment 和 Decrement 方法递增或递​​减变量并将结果值存储在单个操作中。在大多数计算机上,递增变量不是原子操作,需要以下步骤:

将实例变量中的值加载到寄存器中。

增加或减少值。

将值存储在实例变量中。

如果不使用 Increment 和 Decrement,则执行完前两步后可以抢占线程。然后另一个线程可以执行所有三个步骤。当第一个线程恢复执行时,它会覆盖实例变量中的值,并且第二个线程执行的递增或递减的效果丢失。

我发现锁可能会使我的程序失败:)

我的决定正确吗?

p.s ssory 英语不好(

【问题讨论】:

    标签: .net multithreading concurrency


    【解决方案1】:

    成功使用任何并发机制,无论是lock()Interlocked,还是.Net Framework 提供的其他机制,取决于a) 使用满足您要求的最轻量级机制,以及b) 正确实施。

    lock() 可用于确保代码块(lock() 之后的代码)不能被任何其他线程执行,并且还排除了对同时 lock()s 上的任何其他代码块的访问目标在不同的线程中。

    Interlocked 可用于硬件级原子访问特定大小的原始类型 - 通常是指针(在本机代码中)、Int32Int64。这对性能很有好处,但范围有限。

    两者都不是“错误的”,它们只是满足不同的使用模式。在其他情况下(共享数据结构有很多读者和不常写者),您可能更喜欢ReaderWriterLockSlim 而不是Interlockedlock()

    值得指出的是,将Interlockedlock() 混合用于保护对单个原始值的并发访问IS 是错误的,因为lock() 不提供与Interlocked 相同的原子性保证.

    还值得注意的是,您可以通过尽可能完全避免争用来优化性能——不要在线程之间共享数据,选择最佳机制来防止并发访问也没有问题。当然这并不总是可能的,但是 如果你仔细设计你的线程任务,你可以通过 Task Parallel Library 阻止你的线程间通信来避免这个问题。另请查看System.Collections.Concurrent,它提供了您无需自己锁定即可安全访问的集合。

    【讨论】:

    • “并且还排除了对同一目标上 lock() 的任何其他代码块的访问” - 这并不完全正确。如果我从 A 调用 B 并且 A 和 B 都锁定在 C 上,B 可以在同一个线程上执行。
    【解决方案2】:

    联锁语义可以被认为是 ++-- 运算符包裹在 lock 中(分别用于 Interlocked.IncrementInterlocked.Decrement)。

    MSDN 引用的代码不是lock 块内。

    【讨论】:

      【解决方案3】:

      如果您正确使用 lock(object),您的代码应该没问题。互锁只是为某些操作实现线程同步的另一种方法。

      使用锁...

      private int foo;
      private object fooLock = new object();
      
      public void Increment()
      {
          lock (fooLock)
          {
              foo++;
          }
      }
      

      使用联锁...(这应该更快)

      private int foo;
      
      private void Increment()
      {
          Interlocked.Increment(ref foo);
      }
      

      【讨论】:

      • 在每次增加 foo 的地方都使用“fooLock”,但没有其他目的,就等同于在每次增加 foo 的地方都使用“Interlocked.Increment”,但是这两种方法不能混用。否则,如果“foo”为零并且两个线程同时调用两个增量例程,则第一个增量可能会读取 foo 为零,第二个线程读取零并写入一个,而第一个线程写入一个,从而导致增量操作之一“丢失”。
      【解决方案4】:

      不,如果你锁定得当,你应该没问题......因为即使一个线程在复合操作的中间被抢占,另一个线程也无法处理相同的变量,因为它不会'不能获得相同的锁。

      当然,这是假设您为影响相同变量的所有代码都锁定在同一个监视器上。

      【讨论】:

        【解决方案5】:

        lock()Interlocked 的关键在于保持一致。 lock() 根据提供的对象同步代码。如果你有一个lock() 在一个线程中访问变量myVariable,但在另一个线程中访问myVariable 的代码没有锁,那么它是不安全的。同样,如果您在一个地方使用 Interlocked 而在另一个地方不使用,这也不安全。

        【讨论】:

          【解决方案6】:

          Interlocked 类提供线程安全的操作(增量、减量 Excahnage),即使您在不同的内核上。

          所以不用写锁码,你可以使用这个专门的类

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2018-04-28
            • 2016-02-06
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-06-15
            • 2011-06-19
            相关资源
            最近更新 更多