Φροντιστήριο 8 Φύλλο Ασκήσεων UPPAAL - 1 Για του σκοπούς του εργαστηρίου θα χρησιμοποιήσουμε το πρόβλημα του καταστήματος εργασιών, όπως αυτό περιγράφεται το βιβλίο του R. Milner, Communication and Concurrency, Prentice-Hall International, Englewood Cliffs, 1989. Θεωρήστε ότι δύο άνθρωποι μοιράζονται τη χρήση δύο εργαλείων (ενός σφυριού και μιας σφύρας) για να κατασκευάσουν αντικείμενα από απλά συστατικά. Κάθε αντικείμενο δημιουργείται με το να οδηγήσουμε ένα στύλο σε μια βάση. Έστω ότι ένα ζεύγος ενός στύλου και μιας βάσης ονομάζεται εργασία. Οι εργασίες καταφτάνουν σειριακά σε μια ζώνη μεταφοράς και τα ολοκληρωμένα αντικείμενα φεύγουν από μια ζώνη μεταφοράς. Το κατάστημα εργασιών θα μπορούσε να εργοδοτεί οποιοδήποτε αριθμό ανθρώπων (οι οποίοι θα ονομάζονται εργάτες), και οι οποίοι θα μοιράζονταν περισσότερα ή λιγότερα εργαλεία. Σε αυτή τη φάση, ας θεωρήσουμε ότι το κατάστημα εργασιών εργοδοτεί 2 εργάτες και έχει ένα σφυρί και μία σφύρα. Για να γίνει το παράδειγμα πιο συγκεκριμένο, θα θεωρήσουμε ότι η φύση της εργασίας επηρεάζει τις ενέργειες του εργάτη με κάποιο συγκεκριμένο τρόπο: Υποθέστε ότι ο εργάτης θα μπορεί να εκτελέσει εύκολες, δύσκολες ή μεσαίας δυσκολίας εργασίες. Οι εύκολες εργασίες εκτελούνται με τα χέρια, οι δύσκολες εργασίες με το σφυρί και οι άλλες εργασίες είτε με το σφυρί είτε με τη σφύρα.
Κατεβάστε το εργαλείο UPPAAL από τη διεύθυνση www.uppaal.org και κάνετε unzip τα περιεχόμενα του αρχείου. Πατώντας στο αρχείο uppaal.jar ξεκινά η εφαρμογή. The System Editor Θα σχεδιάσουμε το μοντέλο του εργάτη. Στο πεδίο Name αντικαταστήστε το Template με το όνομα του μοντέλου σας, έστω Jobber, και σχεδιάστε το πιο κάτω αυτόματο.
Αφού έχετε κατασκευάσει το πιο πάνω αυτόματο, το μοντέλο σας είναι σχεδόν έτοιμο. Πατήστε στο System declarations που βρίσκεται στο αριστερό παράθυρο. Παρατηρούμε μια οθόνη στην οποία μπορούμε να παραθέσουμε όλα τα αυτόματα του μοντέλου. Όπως έχουμε αναφέρει, στο πρόβλημά μας θα έχουμε δύο εργάτες και γι αυτό δημιουργούμε δύο περιπτώσεις Jobber. Έτσι το μοντέλο μας αποτελείται από δύο αυτόματα τα οποία τρέχουν παράλληλα. Με τη χρήση του πλήκτρου F7 μπορούμε να ελέγξουμε για συντακτικά λάθη. The Simulator Αφού το μοντέλο είναι συντακτικώς ορθό τότε μπορούμε να το προσομοιώσουμε, δηλαδή, να ελέγξουμε το χώρο καταστάσεών του βήμα προς βήμα. Αυτό γίνεται με το να επιλέξουμε το tab Simulator. Προσομοιώνουμε το μοντέλο επιλέγοντας την αντίστοιχη μετάβαση ή αφήνουμε τον προσομοιωτή να εκτελέσει τυχαίες μεταβάσεις. Χρησιμοποιώντας τον προσομοιωτή εντοπίστε ένα μονοπάτι που αντιβαίνει τις αρχικές προδιαγραφές του προβλήματος.
Κανάλια Για να διορθώσουμε το πιο πάνω πρόβλημα που έχουμε εντοπίσει, θα χρησιμοποιήσουμε κανάλια. Για να μοντελοποιήσουμε τον συγχρονισμό μεταξύ των εργατών και των εργαλείων θα χρησιμοποιήσουμε κανάλια. Όταν το get_hammer οριστεί ως κανάλι, τότε οι μεταβάσεις μπορούν να πάρουν τα labels get_hammer! και get_hammer?. Για να δημιουργήσουμε τα κανάλια πατούμε στο (global) project Declarations στον System Editor και προσθέτουμε τα ακόλουθα: // Place global declarations here. chan get_hammer, put_hammer, get_mallet, put_mallet; Αλλάξτε το μοντέλο του εργάτη, έτσι ώστε να γίνει όπως την εικόνα που ακολουθεί. Για να βάλουμε ένα κανάλι στο αυτόματο κάνουμε double click σε μια ακμή και γράφουμε get_hammer! ή get_hammer? στο πεδίο Sync. Χρησιμοποιώντας τον προσομοιωτή παρατηρήστε κατά πόσο οι δύο εργάτες μπορούν να δουλέψουν με το ίδιο εργαλείο. Πιο πρόβλημα έχει δημιουργηθεί τώρα; Μια μετάβαση get_hammer! ή get_hammer? δεν μπορεί ποτέ να εκτελεστεί από μόνη της. Η get_hammer! θα πρέπει να συγχρονίσει με την get_hammer? και αντίστροφα. Για να διορθώσουμε το πιο πρόβλημα του deadlock που έχουμε εντοπίσει θα δημιουργήσουμε ξεχωριστά πρότυπα τόσο για το σφυρί όσο και για τη σφύρα. Για κάθε ένα από τα δύο εργαλεία θα έχουμε δύο locations: ελεύθερο ή κρατημένο. Δημιουργήστε τα πιο κάτω μοντέλα για το σφυρί και τη σφύρα πηγαίνοντας στο Edit->Insert Template και στη συνέχεια προσθέστε τα νέα αυτόματα στο System declarations.
Χρησιμοποιήστε τον προσομοιωτή για να πείσετε τους εαυτούς σας ότι το μοντέλο συμπεριφέρεται όπως θα έπρεπε σύμφωνα με τις αρχικές προδιαγραφές. The verifier Queries Μέσω του Verifier μπορούμε να καθορίσουμε Queries, δηλαδή ιδιότητες τις οποίες θέλουμε να ελέγξουμε κατά πόσο ευσταθούν ή όχι σε κάποιο μοντέλο. Αυτό επιτυγχάνεται με εξαντλητική εξερεύνηση σε όλο το χώρο των καταστάσεων. Diagnostic traces Στην περίπτωση που θέλουμε να δούμε κατά πόσο υπάρχει κατάσταση στην οποία ο ένας εργάτης εργάζεται σε μια μεσαίας δυσκολίας εργασία χρησιμοποιώντας τη σφύρα και ο άλλος
εργάτης εργάζεται σε μια μεσαίας δυσκολίας εργασία χρησιμοποιώντας το σφυρί θα έχουμε την πιο κάτω ιδιότητα: E<> (Jobber1.work_av_mallet && Jobber2.work_av_hammer) Η απάντηση του UPPAAL είναι Property is satisfied. Το UPPAAL πέραν της απάντησης κατά πόσο η πιο πάνω ιδιότητα ισχύει μπορεί να μας δώσει και ένα μονοπάτι το οποίο οδηγεί στην κατάσταση στην οποία ικανοποιείται η ιδιότητα. Το UPPAAL μπορεί να δώσει ένα τέτοιο διαγνωστικό μονοπάτι για τις ιδιότητες Ε<> οι οποίες ευσταθούν και για τις ιδιότητες Α[] οι οποίες δεν ευσταθούν. Για να μπορέσουμε να δούμε το μονοπάτι θα πρέπει να πάμε στο Options->Diagnostic Trace και να επιλέξουμε το Shortest. Στην περίπτωση που επιλέξουμε να φυλαχτεί το μονοπάτι, τότε θα έχουμε τη δυνατότητα να το δούμε στον προσομοιωτή. Μεταβλητές Θα επεκτείνουμε το μοντέλο μας έτσι ώστε οι εργάτες να σταματούν την εργασία τους μόλις έχουν συμπληρώσει συνολικά 10 εργασίες. Για να μοντελοποιήσουμε την επιπλέον απαίτηση θα χρησιμοποιήσουμε μια ακέραια μεταβλητή κατάστασης. Οι τιμές των μεταβλητών αυτών ελέγχονται και ενημερώνονται κατά τις μεταβάσεις. Προσθέστε τις πιο κάτω γραμμές κώδικα στο (global) project Declarations: const int J = 10; int[0,j] jobs; Στην πρώτη γραμμή δηλώνουμε μια ακέραια σταθερά και την θέτουμε ίση με 10. Στη δεύτερη γραμμή δηλώνουμε την ακέραια μεταβλητή με μικρότερη τιμή το 0 και μεγαλύτερη το J. Οι μεταβλητές αρχικοποιούνται με 0. Οι τιμές των ακεραίων μεταβλητών έχουν πάντα όρια. Αν δεν τα θέσουμε εμείς τότε αυτά είναι τα [-32768, 32768]. Θέτουμε τους φρουρούς μεταβάσεων με το να κάνουμε double click σε μια μετάβαση και να τοποθετήσουμε τη συνθήκη στο πεδίο Guard. Στο πεδίο Update της μετάβασης τοποθετούμε τις αυξομειώσεις των ρολογιών. Επεκτείνετε το μοντέλο σας σύμφωνα με το πιο κάτω και στη συνέχεια ελέγξετε με τη χρήση πρώτα του Simulator και στη συνέχεια του Verifier (τις ιδιότητες που είχαμε δει προηγουμένως) το νέο μοντέλο. Τι παρατηρείτε; Τι θα συμβεί αν μεταφέρετε τη μεταβλητή Jobs από το Global Declarations στο Local Declarations τους Jobber;