2012-03-16 50 views
0

我試圖處理非標準數據庫的鎖(即它本身不提供此功能)。我的程序可以獨佔訪問數據庫,但有多個併發線程需要同步。使用散列表鎖定各個數據庫行

我之前使用的天真實現是全局鎖定,不允許並行訪問單獨行(這是由設計總是線程安全的)。

爲了實現這個功能,我的想法是使用一個通用的散列表,它存儲了現在正在使用的所有行標識符。訪問這個哈希表需要同步,通常通過鎖定它。

但是,如果我們發現我們要使用的行已被使用,我們必須等待它被釋放。這不是微不足道的,我的猜測是使用信號等待。

雖然我不確定究竟該怎麼做。你能想出一個實現這個功能的好方法嗎?

回答

0

你對每行使用散列表項的想法很好。作爲這個散列表中的值,我會爲這個特定行存儲一個鎖。任何希望訪問行的線程都會首先檢索(或創建)該哈希表中相應的鎖。然後它會鎖定,然後釋放它。

重要的是,對全局散列表的訪問非常快速。每行有一個鎖對象可以解決該目標,因爲一旦檢索到鎖對象,無論操作持續多久,您都可以立即解鎖散列表。

0

我想出了這個天真的實現。

internal class LockingTest 
{ 
    private readonly Dictionary<string, ReaderWriterLockSlim> _Locks = new Dictionary<string, ReaderWriterLockSlim>(); 

    private void LockRow (string id) 
    { 
     ReaderWriterLockSlim slim; 

     for (; ;) { 
      lock (_Locks) { 
       /* 
       * if row not in use, grab it 
       */ 
       if (!_Locks.TryGetValue (id, out slim)) { 
        slim = new ReaderWriterLockSlim(); // this can probably be replaced by a different, cheap signal class 
        slim.EnterWriteLock(); 
        _Locks.Add (id, slim); 
        return; 
       } 
      } 

      /* 
      * row is in use, wait until released, then try again 
      */ 
      slim.EnterWriteLock(); 
     } 
    } 

    private void UnlockRow (string id) 
    { 
     /* 
     * release and remove lock 
     */ 
     lock (_Locks) { 
      var slim = _Locks[id]; 
      _Locks.Remove (id); 
      slim.ExitWriteLock(); 
     } 
    } 

    public void Test() 
    { 
     var rnd = new Random(); 

     Action thread =() => { 
      for (; ;) { 
       var id = rnd.NextDouble() < 0.5 ? "a" : "b"; 

       Console.WriteLine (Thread.CurrentThread.Name + " waits for " + id); 
       LockRow (id); 
       Console.WriteLine (Thread.CurrentThread.Name + " locked " + id); 
       Thread.Sleep (rnd.Next (0, 100)); 

       UnlockRow (id); 
       Console.WriteLine (Thread.CurrentThread.Name + " released " + id); 
       Thread.Sleep (rnd.Next (0, 100)); 
      } 
     }; 

     new Thread (() => thread()) { 
      Name = "L1", 
      IsBackground = true 
     }.Start(); 

     new Thread (() => thread()) { 
      Name = "L2", 
      IsBackground = true 
     }.Start(); 

     Thread.Sleep (1000); 
    } 

輸出

 
L1 waits for a 
L1 locked a 
L2 waits for b 
L2 locked b 
L2 released b 
L1 released a 
L1 waits for a 
L1 locked a 
L2 waits for a 
L1 released a 
L2 locked a 
L2 released a 
L1 waits for b 
L1 locked b 
L2 waits for b 
L1 released b 
L2 locked b 
L1 waits for a 
L1 locked a 
L2 released b 
L1 released a 
L1 waits for a 
L1 locked a 
L2 waits for a 
L1 released a 
L2 locked a 
L1 waits for b 
L1 locked b 
L1 released b 
L2 released a 
L1 waits for b 
L1 locked b 
L1 released b 
L2 waits for a 
L2 locked a 
L2 released a 
L1 waits for b 
L1 locked b 
L2 waits for a 
L2 locked a 
L2 released a 
L1 released b 
L1 waits for b 
L1 locked b 
L1 released b 
L2 waits for a 
L2 locked a 
L1 waits for a 
L2 released a 
L1 locked a 
L2 waits for b 
L2 locked b 
L1 released a 
L1 waits for b 
L2 released b 
L1 locked b 
L1 released b 
+0

更新的源代碼,包括除了本地鎖全局鎖看到https://github.com/mafutrct/Zysl/blob/master/trunk/Zysl/Utils/BlockingSet。 CS – mafu 2012-03-16 15:10:30