Exercises in this lecture   Go to the notes, in which this exercise belongs -- Keyboard shortcut: 'u'   Alphabetic index   Course home   

Exercise solution 14.2
Opgave om synkroniserede skjalde


Vi skal sikre os, at dirigenten ikke anviser en sanger, som allerede er færdig med at synge. Vi angriber problemet i metoden tagScenen i klassen Dirigent. Vi indfører et boolsk array, færdig, som holder rede på når en sanger er færdig med alle vers. Denne variabel manipuleres gennem metoden af samme navn. Som man nok husker, er udsagnet

  scenenLedig && hvemØnskerAtSynge == næsteSanger
centralt for synkroniseringen mellem sangerne. Udtrykket fortæller under hvilke omstændigheder en bestemt sanger kan få scenen. Vi ændrer nu udsaget til følgende:
  scenenLedig && (hvemØnskerAtSynge == næsteSanger || færdig[enAndenEnd(hvemØnskerAtSynge)])
Med jævne ord, kan en sanger X gå på scenen hvis scenen er ledig OG (hvis der X's tur ELLER hvis den anden sanger er færdig). Vi bekymrer os her kun med situationen, hvor der er to sangere. Her følger min løsning:

/* Synkroniseret koncert, hvor hver skjald synger på skift,
   men hvor den længste sang også synges færdig */

class Skjald extends Thread{
  
  private String[] strofer;
  int forsinkelse;      // pause efter et vers
  int gentagelser;      // hvor mange gange synger jeg verset
  int mig;              // mit nummer
  Dirigent coordinator; // reference til dirigenten

  public Skjald(int mig, Dirigent coordinator, String[] strofer, 
                int forsinkelse, int gentagelser){
    super();
    this.mig = mig;
    this.coordinator = coordinator;
    this.strofer = strofer;
    this.forsinkelse = forsinkelse;
    this.gentagelser = gentagelser;
  }

  // udskriver ét vers ad gangen:
  private void syngVers(){
    coordinator.tagScenen(mig);
    StringBuffer str = new StringBuffer(100);
    for(int i = 0; i < strofer.length; i++){
      str.append(strofer[i] + "\n");
    } 
    System.out.println(str.toString());
    try{
      if (forsinkelse > 0) Thread.sleep(forsinkelse);
    } 
    catch (InterruptedException e) 
      {};
    coordinator.frigivScenen();
  }

  public void run(){
    for(int g = 1; g <= gentagelser; g++){
        syngVers();
    }
    coordinator.færdig(mig);
  }
} // end class Skjald

class Dirigent{
  
  boolean scenenLedig;
  int næsteSanger;
  boolean[] færdig = new boolean[3];  // færdig(i) iff sanger i
                                      // er færdig med sangen

  public Dirigent(int hvemStarter){
    scenenLedig = true; 
    næsteSanger = hvemStarter;
    for(int i = 1; i <= 2; i++) færdig[i] = false;
  }

  private int enAndenEnd(int i){
    if (i == 1) return(2);
    else if (i == 2) return(1);
    else return(0);
  }

  public synchronized void tagScenen(int hvemØnskerAtSynge){
   while (!(scenenLedig && 
             (hvemØnskerAtSynge == næsteSanger ||
              færdig[enAndenEnd(hvemØnskerAtSynge)]))
         ){
    try {
      wait();
    } catch (InterruptedException e) { }
   } // end while
   // scenenLedig && 
   // (hvemØnskerAtSynge == næsteSanger || færdig[enAndenEnd(hvemØnskerAtSynge)])
   scenenLedig = false;
   næsteSanger = enAndenEnd(hvemØnskerAtSynge);
  }

  public synchronized void frigivScenen(){
   scenenLedig = true;
   notifyAll();
  }

  public synchronized void færdig(int hvemFærdig){
    færdig[hvemFærdig] = true;
    notifyAll();
  }

}    

class Sangkor4{

  static String[] mesterJakob = 
    {"MESTER JAKOB, MESTER JAKOB", "SOVER DU, SOVER DU", 
     "HØRER DU EJ KLOKKEN, HØRER DU EJ KLOKKEN", 
     "BIM BAM BUM, BIM BAM BUM"};

  static String[] gladeJul =
    {"Glade jul, dejlige jul", "Engle daler ned i skjul!",
      "Hid de flyver med paradisgrønt", "Hvor de ser, hvad for Gud er kønt", 
     "Lønligt iblandt os de går", "Lønligt iblandt os de går"};


  public static void main(String[] args){
    Dirigent brorKalle = new Dirigent(2); // skjald 1 starter
   
    // virker bedst når der er lige mange vers
    Skjald skjald1 = new Skjald(1, brorKalle, mesterJakob, 1000, 2);
    Skjald skjald2 = new Skjald(2, brorKalle, gladeJul, 200, 5);

    skjald2.start();
    skjald1.start();  
  }
} // end class Sangkor4

Her er endvidere et link til det rene Java program .