User Tools

Site Tools


java:semaphores

Σηματοφορείς

Ο σηματοφορέας είναι μία οντότητα συγχρονισμού μεταξύ ανεξάρτητων ροών εργασίας. Ας υποθέσουμε ότι έχουμε ένα buffer Ν θέσεων μηνυμάτων μέσω του οποίου επικοινωνούν δύο διεργασίες. Αρχικά το buffer είναι άδειο, η διεργασία Α προσθέτει μηνύματα στο buffer και η διεργασία Β τα διαβάζει και τα αφαιρεί από το buffer. Η διαδικασία υπόκειται στους εξής περιορισμούς:

  1. Η διεργασία Β δεν μπορεί να διαβάσει από το buffer εάν το buffer είναι κενό.
  2. Η διεργασία Α δεν μπορεί να γράψει στο buffer εάν το buffer είναι γεμάτο.

Ας υποθέσουμε ότι ορίζουμε ένα σηματοφορέα ως εξής. Αρχικά ο σηματοφορέας έχει μία αρχική ακέραια τιμή μεγαλύτερη ή ίση με το μηδέν. Κάθε φορά που λαμβάνουμε ένα resource (θα εξηγηθεί) η τιμή του σηματοφορέα μειώνεται κατά 1, ενώ κάθε φορά που επιστρέφουμε ένα resource η τιμή αυξάνεται κατά 1. Εάν ο σηματοφορέας λάβει την τιμή μηδέν δεν μπορούμε να λάβουμε άλλο resource και η διεργασία που προσπαθεί να λάβει το resource μπλοκάρει.

Για το παραπάνω πρόβλημα ορίζουμε δύο σηματοφορείς (write και read) ως εξής:

  1. Ένας σηματοφορέας writeSem με αρχική τιμή Ν (Ν permits). Κάθε φορά που γράφουμε 1 μήνυμα στο buffer ο σηματοφορέας μειώνει την τιμή του κατά 1, ενώ κάθε φορά που διαβάζουμε 1 μήνυμα από το buffer ο σηματοφορέας αυξάνει την τιμή του κατά 1.
  2. Ένας σηματοφορεας readSem με αρχική 0. Κάθε φορά που γράφουμε 1 μήνυμα στο buffer ο σηματοφορέας αυξάνει την τιμή του κατά 1, ενώ κάθε φορά που διαβάζουμε 1 μήνυμα από το buffer ο σηματοφορέας μειώνει την τιμή του κατά 1.

Όταν το buffer είναι άδειος ο σηματοφορέας readSem έχει την τιμή 0 και η διαδικασία B μπλοκάρει μέχρι να γραφεί κάτι σε αυτό. Εάν το buffer είναι γεμάτο ο σηματοφορέας write έχει την τιμή 0 και η διαδικασία A μπλοκάρει μέχρι να διαβαστεί κάτι από το buffer.

Ο κώδικας για το γράψιμο και το διάβασμα στο buffer δίνεται σχηματικά ως εξής:

// γράψιμο
  writeSem.down()
  buffer.write(msg);
  readSem.up();
 
// διάβασμα
  String msg;
  readSem.down()
  msg = buffer.read();
  writeSem.up();

Ο κώδικας για ένα σηματοφορέα γενικής χρήσης δίνεται παρακάτω:

Semaphore.java
public class Semaphore {
  byte value = 1;
 
  public Semaphore(byte init_value) {
    value = init_value;
  }
 
  public synchronized void down() {
    while(value==0) {
      try {
        wait();
      } catch(InterruptedException ex) {}
    }
    value--;
  }
 
  public synchronized void up() {
    value++;
    notifyAll();
  }
}
java/semaphores.txt · Last modified: 2017/03/18 21:44 (external edit)