2008-10-21 60 views
4

我试图阻止多线程服务器中的数据竞争。我的问题如下:有一个List<RServer>,类型RServer是一个有几个字段的类。现在,服务器有几个线程同时运行,他们可以修改List(添加更多项目)和个人RServer实例(更改字段)。c#锁定

所以我的策略是让每个RServer情况下,另外一个readonly object RServerListLock = new object()readonly object RServerLock = new object()并在lock附上所有的修改或者(在ListRServer实例)的代码。这安全吗?如果一个线程试图锁定一个RServerLock另一个锁定它会发生什么?

回答

8

如果你有一个竞争锁,第二个线程必须等到第一个释放锁。

你的计划听起来好 - 但你需要的时候数据以及锁定,以确保您获得最新的值,且一致的。否则,你可能会在一个线程中写入一些值的一半,并在一个不同的线程中同时看到一些新的值 - 但可能不是全部 - 和旧值。

如果你可以尽量避免这样做,你的生活会更容易:)不可变的类型使线程更简单。

不要忘记,如果你有代码需要两个锁在同一时间(例如,添加一个RServer并修改另一个,原子地)必须确保您总是以相同的顺序获取锁 - 如果一个线程试图获取锁B,同时它持有锁A,而另一个线程试图获取锁A拿着锁B,你会以僵局结束。

查看我的threading tutorialJoe Albahari's了解更多详情。另外,如果你对并发感兴趣,Joe Duffy有一个excellent book,它即将推出。

0

这是安全的。如果一个线程获取了锁,其他线程将不得不等待,直到锁被释放。

但是,虽然不太可能,但您可能会遇到性能问题,因为锁定可能会超过全局。这真的取决于你的状态是什么以及它是如何被这些线程改变的,所以我不能帮你做到这一点。

0

重申一点 - 每个RServer实例都有一个名为RServerLock的变量,它将使用锁定块进行锁定。

线程1(T1)在RServer 1(R1)上锁定。线程2(T2)尝试修改R1,导致R1锁定块被输入。在这种情况下,T2将等到T1完成。

有一件事要小心的是最终有多少个RServer实例。如果最终导致实例数量过多,那么您只是为了锁定而携带额外的20个字节的数据。此时,您可能需要考虑锁定条带。

2

如果一个线程试图锁定一个已经被锁定的对象,它将会阻塞直到锁定被释放。当两个线程试图同时锁定它时,并不存在并发问题,因为锁是原子操作,并且其中一个线程将始终成为锁的受害者并最终阻塞。

只要您需要RServer实例的完整锁定,您的策略听起来很合理。如果您可以专门锁定特定的RServer实例字段,那可能会更有效。然而,它会增加锁定操作的数量并且会更加复杂。

4

看起来你有一个ReaderWriterLock的主要候选人。最好的类(如果你的运行时支持它,我认为3.0+)是ReaderWriterLockSlim,因为原来的ReaderWriterLock有性能问题。

其中一位MSDN杂志的作者也遇到了RWLS类的问题,我不会在这里详细讨论,但你可以看看它here

我知道下面的代码会产生IDisposable纯粹主义者的愤怒,但有时它确实会产生很好的语法糖。在任何情况下,你可能会发现以下有用:

/// <summary> 
    /// Opens the specified reader writer lock in read mode, 
    /// specifying whether or not it may be upgraded. 
    /// </summary> 
    /// <param name="slim"></param> 
    /// <param name="upgradeable"></param> 
    /// <returns></returns> 
    public static IDisposable Read(this ReaderWriterLockSlim slim, bool upgradeable) 
    { 
     return new ReaderWriterLockSlimController(slim, true, upgradeable); 
    } // IDisposable Read 

    /// <summary> 
    /// Opens the specified reader writer lock in read mode, 
    /// and does not allow upgrading. 
    /// </summary> 
    /// <param name="slim"></param> 
    /// <returns></returns> 
    public static IDisposable Read(this ReaderWriterLockSlim slim) 
    { 
     return new ReaderWriterLockSlimController(slim, true, false); 
    } // IDisposable Read 

    /// <summary> 
    /// Opens the specified reader writer lock in write mode. 
    /// </summary> 
    /// <param name="slim"></param> 
    /// <returns></returns> 
    public static IDisposable Write(this ReaderWriterLockSlim slim) 
    { 
     return new ReaderWriterLockSlimController(slim, false, false); 
    } // IDisposable Write 

    private class ReaderWriterLockSlimController : IDisposable 
    { 
     #region Fields 

     private bool _closed = false; 
     private bool _read = false; 
     private ReaderWriterLockSlim _slim; 
     private bool _upgrade = false; 

     #endregion Fields 

     #region Constructors 

     public ReaderWriterLockSlimController(ReaderWriterLockSlim slim, bool read, bool upgrade) 
     { 
      _slim = slim; 
      _read = read; 
      _upgrade = upgrade; 

      if (_read) 
      { 
       if (upgrade) 
       { 
        _slim.EnterUpgradeableReadLock(); 
       } 
       else 
       { 
        _slim.EnterReadLock(); 
       } 
      } 
      else 
      { 
       _slim.EnterWriteLock(); 
      } 
     } // ReaderWriterLockSlimController 

     ~ReaderWriterLockSlimController() 
     { 
      Dispose(); 
     } // ~ReaderWriterLockSlimController 

     #endregion Constructors 

     #region Methods 

     public void Dispose() 
     { 
      if (_closed) 
       return; 
      _closed = true; 

      if (_read) 
      { 
       if (_upgrade) 
       { 
        _slim.ExitUpgradeableReadLock(); 
       } 
       else 
       { 
        _slim.ExitReadLock(); 
       } 
      } 
      else 
      { 
       _slim.ExitWriteLock(); 
      } 

      GC.SuppressFinalize(this); 
     } // void Dispose 

     #endregion Methods 
    } // Class ReaderWriterLockSlimController 

假如把它放在一个扩展方法类(公共静态类[名])和按如下方式使用它:

using(myReaderWriterLockSlim.Read()) 
{ 
    // Do read operations. 
} 

或者

using(myReaderWriterLockSlim.Read(true)) 
{ 
    // Read a flag. 
    if(flag) 
    { 
    using(myReaderWriterLockSlim.Write()) // Because we said Read(true). 
    { 
     // Do read/write operations. 
    } 
    } 
} 

using(myReaderWriterLockSlim.Write()) // This means you can also safely read. 
{ 
    // Do read/write operations. 
}