Κυριακή, 29 Νοεμβρίου 2015

Έλεγχος στόχων και νήματα επεξεργασίας (Μ2000)

Υπάρχουν πάντα περιθώρια να φτιάχνουμε ένα πολύπλοκο πρόγραμμα χωρίς ιδιαίτερη ουσία! Ένα τέτοιο πρόγραμμα είναι και αυτό εδώ, που βάζει τέσσερα επίπεδα να δουλεύουν με νήματα. Μάλιστα όπως δουλεύουν όλα, κάνει εισαγωγή ένα αλφαριθμητικό (δίνει την εντύπωση ότι θα πάρει αριθμό..).

Στο παράδειγμα θέλουμε να δείξουμε ότι σε κάθε επίπεδο μπορούμε να έχουμε διαφορετικά γράμματα και να γράφουμε κατά βούληση χωρίς να αλλάζει κάτι σε άλλο επίπεδο. Επιπλέον ένα επίπεδο ανοίγει για εισαγωγή και αφού πάρει κάτι (ένα enter είναι Ok) τότε μετράει μερικά νούμερα και "φεύγει". Παράλληλα ένα άλλο επίπεδο κόβει βόλτες παρουσιάζοντας κάποια στοιχεία και έχοντας ένα στόχο όπου η φράση που δείχνει αλλάζει. Μπορούμε να κάνουμε κλικ σε όποιο στόχο θέλουμε και θα ακούσουμε ένα Μπιπ. Μέσα στο αλφαριθμητικό με την οδηγία του στόχου δίνουμε μια εντολή που θα δίναμε με μια Θέσε ή στη γραμμή εντολών. Έτσι αν θέλουμε αντί για το Μπιπ να καλέσουμε ένα τμήμα πρέπει το τμήμα να δηλωθεί ως γενικό. Τμήμα Γενικό Α { }

Μαζί με όλα αυτά θέλουμε να ρυθμίσουμε και την εμφάνιση της βασικής οθόνης και δείχνω πως κάνουμε τον υπολογισμό για να βγάλουμε 8 σειρές! Αυτός ο υπολογισμός έχει να κάνει με το βασικό επίπεδο. Τα άλλα επίπεδα (από 1 έως 32) έχουν μια άλλη πιο εύκολη σχεδίαση. Αρκεί μια εντολή Φόρμα με δυο νούμερα (πλάτος και ύψος) και αυτόματα ρυθμίζονται. Στη βασική φόρμα η χρήση της φόρμας λειτουργεί με αυτόματη απόδοση διάστιχου ή αν χρησιμοποιήσουμε τον χαρακτήρα ";" τότε αφαιρούμε μεν το διάστιχο αλλά κάνουμε και το παράθυρο να πιάνει όλη την οθόνη. Οπότε εδώ το παράθυρό μας θέλουμε να είναι μικρότερο από την οθόνη!

Στο πρόγραμμα φαίνονται οι ορισμοί των νημάτων. Ένα βασικό νήμα είναι το Κύριο.Έργο
Όσο υπάρχουν νήματα το Κύριο.Έργο τρέχει και παράλληλα κοιτάει αν πατήσουμε το δεξί πλήκτρο του ποντικιού για να κάνει μια γενναία έξοδο. Γενναία γιατί πρέπει να πείσει τα νήματα να σταματήσουν! Και αυτό το κάνει στέλνοντας μήνυμα. Αλλά ενδέχεται κάποιο νήμα να πάρει το μήνυμα αλλά να συνεχίζει να λειτουργεί. Το κακό έρχεται αν το τμήμα τερματίσει ενώ υπάρχει νήμα - που ανήκει στο τμήμα. Για την αποφυγή τέτοιας "πλάκας" στέλνουμε ένα δευτερεύον μήνυμα να διαγραφεί όλη η λίστα νημάτων. Ένας άλλο τρόπος είναι να βάλουμε μια Αναμονή 100 ώστε να δώσουμε 100 msec χρόνο να τερματίσει κάποιο "αργοπορημένο" νήμα.

Τα νήματα λειτουργούν κάθε ένα χρονικό διάστημα που ορίζουμε αλλά, υπάρχει ένα αλλά..Αν κάποιο νήμα θέλει περισσότερο χρόνο τότε θα τον πάρει. Αν ο χρόνος που ζητάει είναι από εισαγωγή τότε η εισαγωγή δίνει περιοδικά χρόνο να τρέξουν και άλλα νήματα (ενεργεί σαν το κύριο έργο), ακόμα και το κύριο,έργο.
Δείτε εκεί που γράφει Νήμα και μετά Επίπεδο 2, θα δείτε ότι με μια μεταβλητή μ ορίζουμε ότι στο μ=0 θα κάνουμε εισαγωγή. Αυτό σημαίνει ότι θα κολλήσει το νήμα στην εισαγωγή. Επειδή οι εισαγωγές δίνουν "πάσα" στο σύστημα νημάτων να συνεχίσει, δεν έχουμε μεν πρόβλημα, αλλά τι γίνεται αν εκείνη την ώρα δώσουμε έξοδο από το Κύριο,Έργο..θα γίνει έξοδος ενώ το νήμα θα τρέχει! Ευτυχώς η εντολή που το καθαρίζει είναι η Εισαγωγή Τέλος η οποία στέλνει ένα σήμα και κάνει σαν να πατήσαμε Esc. Αν δεν την δώσουμε αυτή, τότε σίγουρα θα την καθαρίσει η επόμενη...Νήματα Σβήσε (σβήνει όλα τα νήματα, ακόμα και αυτά που τρέχουν σε τμήματα που έχουν καλέσει αυτό --εδώ δεν έχουμε τέτοια περίπτωση).
Στο ίδιο τμήμα δείχνω πως αλλάζω χρόνο "σκανδαλισμού" εντός νήματος. Υπάρχουν και άλλες εντολές όπως η Κράτα (hold) και η Ξεκίνα (restart) καθώς και η Σβήσε (Erase)
(Υπάρχει η Σβήσε (Hide) που μας κάνει αόρατο το επίπεδο, και η Σβήσε στην εντολή νήμα που εξαφανίζει το νήμα, το τερματίζει και το πετάει από την λίστα νημάτων)
(Οι εντολές στα Ελληνικά και Αγγλικά δεν έχουν συσχέτιση στη μετάφραση πάντα όπως σε ένα κανονικό κείμενο Αγγλικών. Εδώ τα γνωστά αναγνωριστικά - οι εντολές και οι συναρτήσεις του περιβάλλοντος- έχουν μια ερμηνεία  σε σχέση με τι κάνει ο διερμηνευτής με αυτά).

Τέλος θα δούμε μια εντολή ΜΕΤΑ 200 { } αυτό όπως και το Κύριο.Έργο είναι αυτόματα τμήματα. Δεν μας δίνουν χειριστή, δηλαδή μεταβλητή για να τα χειριστούμε (μόνο εσωτερικά με την χρήση της Νήμα Αυτό). Η Μετά τρέχει μια φορά μετά το χρόνο που δίνουμε!
Όλα τα νήματα ανήκουν, βλέπουν το τμήμα που τα δημιούργησε και ότι βλέπει αυτό εκτός από το σωρό τιμών. Κάθε νήμα έχει δικό του σωρό τιμών - και εκεί μπορεί να κρατάει στοιχεία χωρίς να καθορίσει το μέγεθός του- ο σωρός αυτό είναι ειδική στοίβα)

Μπορούμε να ορίσουμε μεταβλητές αλλά είναι προτιμότερο να μην το κάνουμε. Τα νήματα παρόλο που ξεκινάνε κάθε συγκεκριμένο χρόνο, έχουν ασύγχρονη λειτουργία αφού μπορούν να αλλάζουν την κατάστασή τους, να σταματούν, να αλλάζουν το χρόνο σκανδαλισμού. Ένα νήμα δεν μπορεί να σκανδαλιστεί δεύτερη φορά ενώ τρέχει διότι κάθε φορά βγαίνει από την λίστα αναμονής και μπαίνει σε μια λίστα εκτέλεσης. Αν έχουμε επιλέξει το ΣΧΕΔΙΟ.ΝΗΜΑΤΩΝ ΤΑΥΤΟΧΡΟΝΟ τότε έχουμε την δυνατότητα να τρέχουμε ανά εντολή το νήμα, και να δίνουμε "πάσα" στο άλλο. Επειδή αυτό είναι ακόμα πιο δύσκολο να ελεγχθεί ότι είναι σε μπλοκ εντολών εκτελείται χωρίς διακοπή. Αυτό διορθώνει λίγο την κατάσταση.
Ένα άλλο θέμα που έχει να κάνει με την ασύγχρονη λειτουργία είναι με το αν μια κατάσταση επιβάλλει την απουσία δράσης! Αυτό πετυχαίνεται με την δομή Μέρος { } ως Χ
(η εντολή ΣΗΜ ή REM είναι σημείωση που επιτρέπει τον χρωματισμό, οπότε παρακάτω δοκιμάστε βάζοντας σε σημείωση τη πρώτη γραμμή)
κκ = ψευδές
Σημ κκ = Αληθές
Μέρος {
      Τύπωσε 1, κκ
} ως κκ
Τύπωσε κκ

Αφού τα νήματα βλέπουν τις μεταβλητές του τμήματος τότε βλέπουν και εκείνες που δηλώνουν ότι κάτι τρέχει και κάτι άλλο δεν θα πρέπει να τρέξει. Θα μπορούσε κανείς σε μια Εισαγωγή να αποκλείσει άλλη εισαγωγή από άλλο νήμα (αν η εντολή εισαγωγής -όχι για αρχείο-  εκτελεστεί ενώ εκτελείται ήδη τότε θα βγει λάθος)
Κάποια στιγμή θα βγει από τον Διερμηνευτή η ασφάλεια του μπλοκ να εκτελείται χωρίς διακοπή, στο σχέδιο.νημάτων ταυτόχρονο. Τότε η Μέρος {} θα έχει περισσότερη αξία.
Τέλος ένα κανόνας για τα νήματα είναι ότι δεν βάζουμε επαναλήψεις (μπορούμε βέβαια) γιατί ένα νήμα (εκτός από αυτό της ΜΕΤΑ) είναι επανάληψη ήδη, άρα αν βάζαμε θα ήταν η δεύτερη επανάληψη, η φωλιασμένη. Σκοπός όμως των νημάτων είναι να κάνουν κάτι σύντομα. Η μόνη αργή περίπτωση είναι η εισαγωγή στοιχείων. Και αυτή γίνεται με τρέξιμο νημάτων εσωτερικά, χωρίς δηλαδή να σταματούν τα άλλα νήματα. Δείτε το παράδειγμα εδώ που δείχνει όλες τις μεθόδους εισαγωγής (δουλεύει και στα δυο σχέδια νημάτων).



Για το παράδειγμα:
Αντιγράψτε το σε ένα τμήμα έστω Παράδειγμα ή Π για πιο σύντομα!
Εδώ τρέχουμε με το εξ ορισμού (από την αρχή δηλαδή) ΣΧΕΔΙΟ.ΝΗΜΑΤΩΝ ΔΙΑΔΟΧΙΚΟ
Παρόλα αυτά βλέπουμε τα πάντα να λειτουργούν "ταυτόχρονα".

\\ ΠΑΡΑΔΕΙΓΜΑ ΜΕ ΤΡΕΙΣ ΣΤΟΧΟΥΣ - ΕΝΑ ΣΕ ΚΑΘΕ ΕΠΙΠΕΔΟ
\\ ΣΤΟΙΧΟΙ ΕΙΝΑΙ ΠΕΡΙΟΧΕΣ ΠΟΥ ΕΛΕΓΧΟΝΤΑΙ ΑΠΟ ΤΟ ΔΕΙΚΤΗ ΤΟΥ ΠΟΝΤΙΚΙΟΥ
Ένταση 100 \\ ρυθμίζουμε τον ήχο
Πένα 0
παλιά_φαρδιά = Φαρδιά
παλιό_διάστιχο = διάστιχο
Φαρδιά 1
Παράθυρο 12, 16000,8000;
Φόρμα 60,30 'υπολογίζει ένα τύπο γραμμάτων για να βγάλει 60Χ30 κείμενο σε 16000Χ8000 twips
\\ θέλουμε όμως να κόψουμε λίγο την οθόνη
ύψος_γραμμής=(υ.σημεία-διάστιχο*ύψος)/ύψος
\\ θέλουμε 8 τέτοιες γραμμές με διάστιχο 0
διάστιχο 0
\\ τα χ.σημεια μας έχουν δώσει 60 χαρακτήρες
\\ οπότε  τα 2/3 θα μας δώσουν 40
τύπος Τύπος, χ.σημεια*2/3,ύψος_γραμμής*8
Οθόνη #1234FF \\ χρώμα σε Html κωδικό
Κίνηση 2000, 4000 \\ μετακινούμε την οθόνη στο παράθυρο
Περιθώριο {
      \ Μπορούμε να χρησιμοποιήσουμε το περιθώριο για δεύτερη οθόνη
      Διάστιχο 60
      Πένα 7
      \
      \* Στόχος στο επίπεδο που λέμε Περιθώριο *\
      \
      Φαρδιά 0 : Πλάγια 1 : Οθόνη 6 ' το 6 είναι ένα από τα 16 βασικά χρώματα (0...15)
      Αναφορά "Περιθώριο"
      Τύπωσε
      Τύπωσε μέρος Διάστιχο ' η μέρος βάζει πρόσκαιρα αναλογική γραφή και δεν αλλάζει γραμμή.
      \\ το @(1,2) είναι σαν την εντολή Δρομέας
      Τύπωσε μέρος @(1,2), $(4), Γραμματοσειρά$
      \\ οι στόχοι προγραμματίζονται βάσει εγχειριδίου
      \\ βάλε βοήθεια στόχος  στη γραμμή εντολών ή καλύτερα
      \\ κάνε επιλογή τη λέξη και πάτε ctrl+F1
      Δρομέας 13,4 : Στόχος Χειριστής1,"Μπιπ", 12, 1, 13, 5, 104, "πάτα εδώ"
      Στη εδώ.χ=χ.σημεία, εδώ.υ=υ.σημεία
}
\
\* Στόχος στο βασικό επίπεδο  *\
\
Αναφορά "Βασικό Επίπεδο"
Δρομέας 0,3
Τύπωσε Γραμματοσειρά$, πλάτος
Δρομέας 13,2
Στόχος Χειριστής2, "Μπιπ", 12, 1, 13, 5, 106, "πάτα εδώ"
\\ η εντολή επίπεδο χωρίς αριθμό ανοίγει ένα μπλοκ εντολών
\\  για τη βασική οθόνη (μπορούμε να έχουμε φωλιασμένα μπλοκ πολλών επιπέδων)
Επίπεδο { Οθόνη #ffaa22, -3 }
Διαμέσου Δεύτερο ' καλούμε μια υπορουτίνα (απλή ρουτίνα)  για καθορισμό επιπέδου 1
Επίπεδο 1 {
      \* Στόχος  στο επίπεδο 1  *\
      \ Τα επίπεδα 1 έως 32 αντιστοιχούν στους Παίκτες 1 έως 32
      \ Μπορούμε δηλαδή να τα χρησιμοποιούμε με διαφορετικό τρόπο
      \ η προσαρμογή (interface) αλλάζει, όχι το αντικείμενο.
      \ Έτσι ένα παίκτη μπορούμε να τον κάνουμε μια άλλη οθόνη (Επίπεδο).
      Δρομέας 0,3: Τύπωσε Γραμματοσειρά$
      \ τυπώνω το διάστιχο σε twips, τα πλάτος και ύψος σε χαρακτήρες
      Δρομέας 0,4: Τύπωσε Διάστιχο, Πλάτος, Ύψος
      Δρομέας 13,1
      Στόχος Χειριστής3, "Μπιπ",12,1,13,5,105,"πάτα εδώ"   \\  άλλαξε με αυτό "Μπιπ: Set End"
      Άναψε   ' αντίθετη εντολή σβήσε - τα επίπεδα πρέπει να "ανάψουν" (εξ ορισμού είναι σβηστά)
}
\* εδώ ετοιμάζω ένα ακόμα επίπεδο
\* το 2 είναι πάντα πάνω από το 1 , όπως το 32 πάνω από όλα!
Επίπεδο 2 {
\\ εδώ δίνω ένα βασικό μέγεθος γραμμάτων αλλά παρακάτω με τη φόρμα θα το αλλάξω
\\ σημασία έχει ότι δίνω το μέγεθος του επιπέδου σε 10000 twips πλάτος και 1000 twips ύψος
Παράθυρο 10, 10000,1000
Φόρμα 20,2
Κίνηση 10000,0
Άναψε  \\ αυτό για το επίπεδο 2
}
Άναψε  \\ αυτή πάει για τη βασική οθόνη (όλα μαζί)
μ=0
\\ Χρησιμοποιώ νήματα για να τρέξω το παράδειγμα
Νήμα {
Επίπεδο 2 {
      Αν μ=0 Τότε {
            κάτι$="0    "
            Πεδίο 0,0,5 ως κάτι$
            \ συχρονίζω το νήμα γιατί έχει πάρει πολύ χρόνο
            \ από την προηγούμενη εντολή
            Νήμα αυτό κάθε 20
      }
      μ=μ+1
      Τύπωσε
      Τύπωσε μ,  ' για να γράφει η τελευταί γραμμή χωρίς να βλέπουμε την ολίσθηση με κενή γραμμή!
      Ανανέωση   \\ αλλιώς δεν το βλέπουμε άμεσα
      Αν μ>50 Τότε Μετά 200 { Σβήσε } : Νήμα Αυτό Σβήσε 


      }
 } ως νημα1 κάθε 10
\\ τα νήματα δεν έχουν ονόματα αλλά μεταβλητές χειρισμού
\\ όπως και οι στόχοι
Νήμα { Περιθώριο {
\\ χρησιμοποιώ την Τύπωσε Πάνω γιατί σβήνει το περιεχόμενο της γραμμής πρώτα
\\ η μεταβλητή μόνο ανάγνωσης Τώρα δίνει την ώρα!
\\ η Τύπωσε Υπό κάνει αλλαγή γραμμής αφού κάνει υπογράμμιση
Δρομέας 0,6: Τύπωσε Πάνω $(6), γραφή$(Τώρα,"hh:mm:ss") : Τύπωσε Υπό
} }ως νημα2 κάθε 40
\
\* βάζω σε κάθε επίπεδο μια εργασία με ένα νήμα ή περισσότερα!
\
ι=0
Νήμα {Επίπεδο { Τύπωσε : Τύπωσε ι, : ι++ : Ανανέωση
' με τον παραπάνω τρόπο, πρώτα αλλάζουμε γραμμή
' μετά τυπώνουμε το ι με το κόμμα που κολλάει το δρομέα στην επόμενη στήλη
} } ως νήμα3 κάθε 100 '  κάθε δέκατο του δευτερολέπτου


κ=Αληθής ' υπάρχει και σαν Αληθές
Νήμα { Επίπεδο 1 {
      \\ ο χειριστής ~ κάνει αυτο κ = όχι κ δηλαδή αντιστρέφει το Αληθής με το Ψευδής
      κ~
      \\ Η εντολή Αλλαγή παίρνει παραμέτρους με όνομα!
      \\ Δείτε ότι χρησιμοποιούμε την μεταβλητή Χειριστής3 για να αλλάξουμε φράση στο στόχο
      \\ Η μεταβλητή μόνο ανάγνωσης Τικ δίνει το μετρητή βημάτων των νημάτων
      \\ (δεν έχει άμεση σχέση με το χρόνο, τα βήματα μπορούν να επιταχυνθούν)
      Αν κ Τότε { Αλλαγή Χειριστής3, Φράση γραφή$(τικ) } Αλλιώς Αλλαγή Χειριστής3, Φράση "πάτα εδώ"
      }
      } ως νήμα4 κάθε 600
 
Νήμα {
      Επίπεδο 1 {
      Κίνηση τυχαίος(εδώ.χ-3000), τυχαίος(εδώ.υ-3000)
      Δρομέας 0,5
      \\ η Τύπωσε Πάνω καθαρίζει τη γραμμή και κάνει πρόσκαιρα το πλάτος στήλης όσο η γραμμή, η $(6) βάζει στοίχιση κέντρο
       Τύπωσε Πάνω $(6), Μορφή$("Κορυφή {1}, Αριστερά {0}",κίνηση.χ, κίνηση.υ)
       Τύπωσε Υπό
       Τύπωσε Πάνω $(6), Μορφή$("Κορυφή {1}px, Αριστερά {0}px",κίνηση.χ δια πλάτος.σημείου, κίνηση.υ δια ύψος.σημείου)
       }
} ως νήμα5 κάθε 3000 \\ κάθε3 δευτερόλεπτα
Κύριο.Έργο 20 {
     \\ πρέπει να σαρώνουμε - δηλαδή να τρέχουμε μια εσωτερική λειτουργία
     \\ στην οποία ελέγχονται οι στόχοι
     Σάρωσε 0.1
     \\  εδώ κοιτάμε αν πατήθηκε το δεξί πλήκτρο του ποντικιού
      Αν Δείκτης=2 Τότε Έξοδος
}

Εισαγωγή Τέλος
    
\* Κανονικά στην έξοδο από το κύριο έργο τερματίζουν και τα νήματα του τμήματος
\* όμως πέρνει την εντολή ότι είναι στην λίστα αναμονής
\* και αυτό που τρέχει θα το λάβει στο τέλος, εκτός και αν το αναγκάσουμε όπως εδώ:
Νήματα Σβήσε


\* Καθαρίζουμε όλα τα επίπεδα (εκτός από το βασικό και το Περιθώριο)
Παίκτης 0
\*  Και οι στόχοι εξαφανίζονται ή επιλεκτικά με τον επανακαθορισμό του παραθύρου
\* ή απευθείας για όλους
Στόχοι Νέοι
\* η εντολή Παράθυρο σε ένα επίπεδο αναφέρεται στο επίπεδο, αλλά γενικά
\* καθορίζει  το παράθυρο του περιβάλλοντος
\* με μηδέν για πλάτος το παράθυρο θα καταλάβει όλη την επιφάνεια εργασίας
Διάστιχο παλιό_διάστιχο
Παράθυρο 12, 0
Περιθώριο {Οθόνη 1}
\* Τώρα καθορίζω και την βασική οθόνη
Φαρδιά παλιά_φαρδιά
Φόρμα 60,25 : Οθόνη 2 : Πένα 15
' Εδώ κάνω έξοδο γιατί έχω υπορουτίνα παρακάτω!
Έξοδος


Δεύτερο:
      \* φτιάχνουμε το Επίπεδο 1 χωρίς να το δείχνουμε!
      Επίπεδο 1 {
            Γραμματοσειρά "TAHOMA"
            Φαρδιά 1
            Διάστιχο 0 \\ Ξεκινάμε με 0 για να πάρουμε τα μέτρα μας!
            Παράθυρο 12, 7000,4500 \\ βάζουμε 12pt γράμματα, θα αλλάξει στην Φόρμα
            Φόρμα 30,7 \\ Θα φτιάξουμε 30x7 κείμενο σε 7000x4500 twips
            \* Η εντολή φόρμα θα κόψει το περίσσευμα σε εικονοστοιχεία
            \* και πιθανόν θα βάλει διάστιχο για να καλύψει περισσότερο χώρο (στα 4500 twips)
            \* Μπορούμε να διαβάσουμε το μέγεθος των γραμμάτων που υπολόγισε η Φόρμα
            \* με την εσωτερική μεταβλητή Τύπος
            Οθόνη 2 ' πράσινη
            Αναφορά Μορφή$("Επίπεδο 1  {0}X{1} and γραμματοσειρά {2}pt, διάστιχο {3}", Πλάτος, Ύψος, Τύπος, Διάστιχο)
       
           Σημ 1. Αναφορά Μορφή$("Σε twips  {0}X{1}", χ.σημεία, υ.σημεία)
           Σημ 2. Αναφορά Μορφή$("Κορυφή {0}, Αριστερά {1}", κίνηση.χ, κίνηση.υ)
           Κίνηση 100, 2000 ' ίδιο με αυτό: Παίκτης 1, 100,2000
           Άναψε                          ' ίδιο με αυτό:Παίκτης 1 Δείξε
      }
      \* χωρίς την επιστροφή δεν μπορούμε να γυρίσουμε στη κλήση μετά την Διαμέσου
Επιστροφή


Δεν υπάρχουν σχόλια:

Δημοσίευση σχολίου