PROGRAMOWANIE W ŚRODWISKU SIECIOWYM I

 

ĆWICZENIE III

 

Read / Write Lock Java Implementation

 

Read Access   

Żaden z wątków nie zapisuje, żaden z wątków nie czeka na zapis

Write Access   

Żaden z wątków nie czyta ani nie zapisuje

 

public class ReadWriteLock{
 
  private int readers       = 0;
  private int writers       = 0;
  private int writeRequests = 0;
 
  public synchronized void lockRead() throws InterruptedException{
    while(writers > 0 || writeRequests > 0){
      wait();
    }
    readers++;
  }
 
  public synchronized void unlockRead(){
    readers--;
    notifyAll();
  }
 
  public synchronized void lockWrite() throws InterruptedException{
    writeRequests++;
 
    while(readers > 0 || writers > 0){
      wait();
    }
    writeRequests--;
    writers++;
  }
 
  public synchronized void unlockWrite() throws InterruptedException{
    writers--;
    notifyAll();
  }
}

 

Read / Write Lock Reentrance

 

public class ReadWriteLock{
 
  private Map<Thread, Integer> readingThreads =
      new HashMap<Thread, Integer>();
 
  private int writers        = 0;
  private int writeRequests  = 0;
 
  public synchronized void lockRead() throws InterruptedException{
    Thread callingThread = Thread.currentThread();
    while(! canGrantReadAccess(callingThread)){
      wait();                                                                   
    }
 
    readingThreads.put(callingThread,
       (getAccessCount(callingThread) + 1));
  }
 
 
  public synchronized void unlockRead(){
    Thread callingThread = Thread.currentThread();
    int accessCount = getAccessCount(callingThread);
    if(accessCount == 1){ readingThreads.remove(callingThread); }
    else { readingThreads.put(callingThread, (accessCount -1)); }
    notifyAll();
  }
 
 
  private boolean canGrantReadAccess(Thread callingThread){
    if(writers > 0)            return false;
    if(isReader(callingThread) return true;
    if(writeRequests > 0)      return false;
    return true;
  }
 
  private int getReadAccessCount(Thread callingThread){
    Integer accessCount = readingThreads.get(callingThread);
    if(accessCount == null) return 0;
    return accessCount.intValue();
  }
 
  private boolean isReader(Thread callingThread){
    return readers.get(callingThread) != null;
  }
 
}

 

Write Reentrance

 

public class ReadWriteLock{
 
    private Map<Thread, Integer> readingThreads =
        new HashMap<Thread, Integer>();
 
    private int writeAccesses    = 0;
    private int writeRequests    = 0;
    private Thread writingThread = null;
 
  public synchronized void lockWrite() throws InterruptedException{
    writeRequests++;
    Thread callingThread = Thread.currentThread();
    while(! canGrantWriteAccess(callingThread)){
      wait();
    }
    writeRequests--;
    writeAccesses++;
    writingThread = callingThread;
  }
 
  public synchronized void unlockWrite() throws InterruptedException{
    writeAccesses--;
    if(writeAccesses == 0){
      writingThread = null;
    }
    notifyAll();
  }
 
  private boolean canGrantWriteAccess(Thread callingThread){
    if(hasReaders())             return false;
    if(writingThread == null)    return true;
    if(!isWriter(callingThread)) return false;
    return true;
  }
 
  private boolean hasReaders(){
    return readingThreads.size() > 0;
  }
 
  private boolean isWriter(Thread callingThread){
    return writingThread == callingThread;
  }
}

 

 

Read to Write Reentrance

 

public class ReadWriteLock{
 
    private Map<Thread, Integer> readingThreads =
        new HashMap<Thread, Integer>();
 
    private int writeAccesses    = 0;
    private int writeRequests    = 0;
    private Thread writingThread = null;
 
  public synchronized void lockWrite() throws InterruptedException{
    writeRequests++;
    Thread callingThread = Thread.currentThread();
    while(! canGrantWriteAccess(callingThread)){
      wait();
    }
    writeRequests--;
    writeAccesses++;
    writingThread = callingThread;
  }
 
  public synchronized void unlockWrite() throws InterruptedException{
    writeAccesses--;
    if(writeAccesses == 0){
      writingThread = null;
    }
    notifyAll();
  }
 
  private boolean canGrantWriteAccess(Thread callingThread){
    if(isOnlyReader(callingThread))    return true;
    if(hasReaders())                   return false;
    if(writingThread == null)          return true;
    if(!isWriter(callingThread))       return false;
    return true;
  }
 
  private boolean hasReaders(){
    return readingThreads.size() > 0;
  }
 
  private boolean isWriter(Thread callingThread){
    return writingThread == callingThread;
  }
 
  private boolean isOnlyReader(Thread thread){
      return readers == 1 && readingThreads.get(callingThread) != null;
  }
  
}

 

 

Write to Read Reentrance

 

public class ReadWriteLock{
 
    private boolean canGrantReadAccess(Thread callingThread){
      if(isWriter(callingThread)) return true;
      if(writingThread != null)   return false;
      if(isReader(callingThread)  return true;
      if(writeRequests > 0)       return false;
      return true;
    }
 
}

 

 

Fully Reentrant ReadWriteLock

 

public class ReadWriteLock{
 
  private Map<Thread, Integer> readingThreads =
       new HashMap<Thread, Integer>();
 
   private int writeAccesses    = 0;
   private int writeRequests    = 0;
   private Thread writingThread = null;
 
 
  public synchronized void lockRead() throws InterruptedException{
    Thread callingThread = Thread.currentThread();
    while(! canGrantReadAccess(callingThread)){
      wait();
    }
 
    readingThreads.put(callingThread,
     (getReadAccessCount(callingThread) + 1));
  }
 
  private boolean canGrantReadAccess(Thread callingThread){
    if( isWriter(callingThread) ) return true;
    if( hasWriter()             ) return false;
    if( isReader(callingThread) ) return true;
    if( hasWriteRequests()      ) return false;
    return true;
  }
 
 
  public synchronized void unlockRead(){
    Thread callingThread = Thread.currentThread();
    if(!isReader(callingThread)){
      throw new IllegalMonitorStateException("Calling Thread does not" +
        " hold a read lock on this ReadWriteLock");
    }
    int accessCount = getReadAccessCount(callingThread);
    if(accessCount == 1){ readingThreads.remove(callingThread); }
    else { readingThreads.put(callingThread, (accessCount -1)); }
    notifyAll();
  }
 
  public synchronized void lockWrite() throws InterruptedException{
    writeRequests++;
    Thread callingThread = Thread.currentThread();
    while(! canGrantWriteAccess(callingThread)){
      wait();
    }
    writeRequests--;
    writeAccesses++;
    writingThread = callingThread;
  }
 
  public synchronized void unlockWrite() throws InterruptedException{
    if(!isWriter(Thread.currentThread()){
      throw new IllegalMonitorStateException("Calling Thread does not" +
        " hold the write lock on this ReadWriteLock");
    }
    writeAccesses--;
    if(writeAccesses == 0){
      writingThread = null;
    }
    notifyAll();
  }
 
  private boolean canGrantWriteAccess(Thread callingThread){
    if(isOnlyReader(callingThread))    return true;
    if(hasReaders())                   return false;
    if(writingThread == null)          return true;
    if(!isWriter(callingThread))       return false;
    return true;
  }
 
 
  private int getReadAccessCount(Thread callingThread){
    Integer accessCount = readingThreads.get(callingThread);
    if(accessCount == null) return 0;
    return accessCount.intValue();
  }
 
 
  private boolean hasReaders(){
    return readingThreads.size() > 0;
  }
 
  private boolean isReader(Thread callingThread){
    return readingThreads.get(callingThread) != null;
  }
 
  private boolean isOnlyReader(Thread callingThread){
    return readingThreads.size() == 1 &&
           readingThreads.get(callingThread) != null;
  }
 
  private boolean hasWriter(){
    return writingThread != null;
  }
 
  private boolean isWriter(Thread callingThread){
    return writingThread == callingThread;
  }
 
  private boolean hasWriteRequests(){
      return this.writeRequests > 0;
  }
 
}

 

Calling unlock() From a finally-clause

 

lock.lockWrite();
try{
  //do critical section code, which may throw exception
} finally {
  lock.unlockWrite();
}

 

 

Materiał:

 

http://tutorials.jenkov.com/java-concurrency/read-write-locks.html

 

 

ZADANIE

1)     Zaimplementować przesyłanie plików na serwer i pobieranie plików z  serwera z wykorzystaniem gniazdek jako aplikacje w architekturze klient – serwer.

2)     Zapis oraz odczyt plików z wykorzystaniem klasy ReadWriteLock podanej na stronie.

3)     Dodatkowo zaimplementować polecenie przesłania zawartości danego katalogu roboczego (polecenie LIST).

 

Aplikacja powinna rozszerzać funkcjonalność z aplikacji z ćwiczenia II.

 

Klient podczas wysyłania polecenia file, podaje nazwę pliku do przesłania z serwera. Serwer przy starcie powinien utworzyć obiekt klasy ReadWriteLock. Serwer po odebraniu połącznenia z klientem, utworzeniu wątku klienta powinien przekazać do wątku klienta obiekt klasy ReadWriteLock. Wątek klienta na serwerze odczytuje polecenie file, wywołuje metodę lock.lockRead, spowoduje to odczekanie do chwili gdy nikt nie zapisuje do katalogu roboczego i wtedy po uzyskaniu dostępu do odczytu, odczytuje plik, zwalnia lock wywołując metodę unlockRead i przesyła plik do klienta.