2011-04-05 4 views
0

Я пишу реализацию Java для двухфазной блокировки. Итак, я использую блокировку Reentrant (блокировка ReadWrite). Проблема в том, что когда поток выполняет lock.readLock.lock() или lock.writeLock(). Lock(), и блокировка уже заблокирована, он застрял навсегда, даже когда блокировка разблокирована с помощью lock.readLock(). Unlock() или lock.writeLock(). unlock(). Итак, похоже, что разблокировка не пробуждает официантов !!! вот код, который вызывает проблему:Поток заблокирован навсегда при ожидании операции блокировки

class LockTable 
{ 
// /******************************************************************************* 
//  * This class is used to represent an individual lock. 
//  * @param tid  the id of the transaction holding the lock 
//  * @param shared whether the lock is shared (true) or exclusive (false) 
//  */ 
// void Lock (int tid, boolean shared) 
// { 
//  Semaphore sem = new Semaphore (0); 
// } // Lock class 

    /** Associative map of locks held by transactions of the form (key = oid, value = lock) 
    */ 
    private HashMap<Integer,MyLock> locks; 

    public LockTable(){ 
     locks= new HashMap<Integer,MyLock>(); 

    } 

    /******************************************************************************* 
    * Acquire a shared/read lock on data object oid. 
    * @param tid the transaction id 
    * @param oid the data object id 
    */ 
    void rl (int tid, int oid) throws InterruptedException 
    { 

     MyLock lock=null; 
     boolean wait = false; 
     synchronized(this) { 
      try { 
       lock = locks.get(oid);    // find the lock 

       if((lock != null) && (lock.lock.isWriteLocked())){ 

        wait = true; 

        // System.out.println(locks.get(oid).shared); 
       } 

       if(lock == null){ 
       lock = new MyLock(tid, true); 
       lock.lock.readLock().lock(); 
       lock.readers.add(tid); 
       locks.put(oid, lock); 
       } 

      } catch(Exception e) { 
       System.out.println(e.getStackTrace());  // lock not found, so oid is not locked; 
      } // try 
     }//synch 


     if (wait){ 

      System.out.println("Transaction " + tid + " is waiting.."); 
      Main.g.addEdge(tid, lock.tid); 
        if(Main.g.hasCycle()) 
         restart(tid); 

      //to exclude the restarted thread 
      if(!Main.trans[tid].terminate){ 

       lock.lock.readLock().lock(); 
       Main.g.removeEdge(tid, lock.tid); 
       synchronized(this){ 
       lock.readers.add(tid); 
       }//synchronized 
      }//if isInturrupted 
      else 
       return; 
     } 
     else 
     synchronized(this) { 
       lock.lock.readLock().lock(); 
       lock.readers.add(tid); 
     } // synchronized 

    } // rl 

    /******************************************************************************* 
    * Acquire an exclusive/write lock on data object oid. 
    * @param tid the transaction id 
    * @param oid the data object id 
    */ 
    void wl (int tid, int oid) throws InterruptedException 
    { 
     //type to determine the last lock type in order 
     //to be able to remove the edges from waitfor graph 
     int type = 0; 
     MyLock lock = null; 
     boolean wait = false; 

     synchronized(this) { 
      try { 
       lock = locks.get(oid);    // find the lock 
       if(lock != null && (lock.lock.isWriteLocked() || lock.readers.size() > 0)) 
       { 
        wait = true; 
       } 
       if(lock == null){ 
        lock = new MyLock(tid); 
        lock.lock.writeLock().lock(); 
        locks.put(oid,lock); 
       } 
      } catch(Exception e) { 
       System.out.println(e.getStackTrace());  // lock not found, so oid is not locked; 
      } // try 
     } 
     if (wait){ 
       System.out.println("Transaction " + tid + " is waiting.."); 
       if(lock.lock.isWriteLocked()) 
        Main.g.addEdge(tid, lock.tid); 
       else{ 
        type = 1; 
        for(int reader : lock.readers) 
         Main.g.addEdge(tid, reader); 
        }//else 

          if(Main.g.hasCycle()) 
          { 
           restart(tid); 
          }//if 
      if(!Main.trans[tid].terminate){ 
       System.out.println("I'm waiting here in wl"); 
       lock.lock.writeLock().lock(); 
       System.out.println("Wakeup.."); 
       if(type == 0) 
        Main.g.removeEdge(tid, lock.tid); 
       else 
        for(int reader : lock.readers) 
         Main.g.removeEdge(tid, reader); 
       lock.tid = tid; 
      } 
      else 
       return; 

     }// if(wait) ==> for the lock to be released 
     else 
      lock.lock.writeLock().lock(); 

    } // wl 

    void restart(int tid){ 
    synchronized(this) { 
     MyLock lock; 
     List<Integer> toRemove = new ArrayList(); 
     for(int i : locks.keySet()){ 
      lock = locks.get(i); 

       //lock.sem.release(); 
       if(lock.lock.isWriteLockedByCurrentThread()){ 

        System.out.println("Transaction"+tid+" unlock object "+ i +" in order to restart"); 
        lock.lock.writeLock().unlock(); 
        System.out.println("number of write holders: " + lock.lock.writeLock().getHoldCount()); 
        System.out.println("number of read holders: " + lock.lock.getReadHoldCount()); 
        System.out.println("number of waiters: " + lock.lock.getQueueLength()); 
        toRemove.add(i); 

       } 
      if(!lock.lock.isWriteLocked()) 
       if(lock.readers.contains(tid)){ 
        // lock.numberOfReaders --; 

         System.out.println("Transaction"+tid+" unlock object "+ i +" in order to restart"); 
         lock.readers.remove(lock.readers.indexOf(tid)); 
         lock.lock.readLock().unlock(); 
         System.out.println("number of write holders: " + lock.lock.getWriteHoldCount()); 
         System.out.println("number of read holders: " + lock.lock.getReadHoldCount()); 
         System.out.println("number of waiters: " + lock.lock.getQueueLength()); 
         toRemove.add(i); 

        }//if 
     }//for 
     for(int i = 0; i < toRemove.size() ; i ++) 
      locks.remove(toRemove.get(i)); 
     Main.g.removeEdges(tid); 

     // Thread.currentThread().interrupt(); 
     Main.trans[tid].terminate = true; 

     System.out.println("Transaction" + tid + " restarted"); 

     }//sync 
    } 

    /******************************************************************************* 
    * Unlock/release the lock on data object oid. 
    * @param tid the transaction id 
    * @param oid the data object id 
    */ 
    void ul (int tid, int oid) 
    { 
     MyLock lock = null; 
     boolean error = false; 
     synchronized(this) { 
      try { 
       lock = locks.get(oid);     // find the lock 
       if(lock == null) 
        System.out.println("println: lock not found"); 

      } catch(Exception e) { 
       System.out.println("lock not found"); // lock not found 
      } // try 
     }//sync 
      if((lock != null) && (lock.lock.isWriteLockedByCurrentThread())){ 

         System.out.println("tid: " + tid + " unlock object: " + oid); 
         lock.lock.writeLock().unlock(); 
         System.out.println("done with unlock"); 
         System.out.println("number of write holders: " + lock.lock.writeLock().getHoldCount()); 
         System.out.println("number of read holders: " + lock.lock.getReadHoldCount()); 
         System.out.println("number of waiters: " + lock.lock.getQueueLength()); 
      }// if lock != null 
      else 
       if((lock != null) && (lock.readers.size()>0)){ 
        if(lock.readers.contains(tid)){ 
        lock.readers.remove(lock.readers.indexOf(tid)); 
        lock.lock.readLock().unlock(); 
        System.out.println("Transaction"+tid+" unlocked shared lock on object "+oid); 
        //System.out.println("number of write holders: " + lock.lock.readLock().); 
        System.out.println("number of read holders: " + lock.lock.getReadHoldCount()); 
        System.out.println("number of waiters: " + lock.lock.getQueueLength()); 

        }//if lock.readers 
       }//if 


     if (error) 
      System.out.println ("Error: ul: no lock for oid = " + oid + " found/owned"); 
    } // ul 
+0

Вы можете немного почистить это и оставить только соответствующие строки кода? Немного трудно читать ... – mre

+0

Какой выход вы получаете, и какой результат вы ожидали? Ваш пример не является исполняемым, поэтому мы не можем его попробовать. –

+0

Кроме того, вы можете использовать инструмент 'jstack', чтобы посмотреть состояние стека всех ваших потоков, когда они застряли. Он показывает вам, какая нить держит, которая блокируется, и которая ждет, на какой блокировке. –

ответ

4
Method A: 
...snip... 
synchronized(this) { 
    ...snip... 
    lock.lock.readLock().lock(); 
    ...snip... 
} 

Method B: 
...snip... 
synchronized(this) { 
    ...snip... 
    lock.lock.readLock().unlock(); 
    ...snip... 
} 

Проблема у Вас есть тупиковый от блокировки в основном на одном синхронизатора, удерживая другой. Когда вы вызываете Lock.lock() внутри блока кода synchronized(this), Thread войдет в состояние BLOCKING, продолжая удерживать встроенный замок на this. Поскольку Thread, который фактически удерживает Lock для получения встроенной блокировки на this, а встроенный -lock никогда не будет выпущен, у вас есть тупик.

Например:
Резьба1 входит Способ А, получает блокировку на this
thread2 входят метод А, не может получить this так блоки
Резьба1 получает для
блокировки чтения Резьба1 выпускает this
Резьба2 получает this
Блок Thread2, ожидающий Readlock
Thread1 вводит метод B, не может получить this, поэтому блоки
заблокирован

+0

+1, отличное объяснение! –

0

также, не забудьте про несчастливый путь. убедитесь, что вы положили свою разблокировку() внутри finally, иначе, если исключение будет выбрано, unlock() никогда не вызывается, и вы оказываетесь в тупике.

Смежные вопросы