Επόμενο:ΠΑΡΑΛΛΗΛΗ ΤΑΞΙΝΟΜΗΣΗ Πάνω: Διάφορα Προβλήματα Παράλληλου Προγραμματισμού Πίσω: ΟΙ ΓΕΥΜΑΤΙΖΟΝΤΕΣ ΦΙΛΟΣΟΦΟΙ
ΣΥΣΤΗΜΑ ΚΕΝΤΡΙΚΗΣ ΘΕΡΜΑΝΣΗΣ
Το πρόγραμμα που ακολουθεί αποτελεί παράδειγμα συγχρονικής
προσομοίωσης ενός πολυεργασιακού συστήματος ελέγχου διεργασιών (process control). Πρόκειται γιά ένα
σύστημα κεντρικής θέρμανσης. Θα μπορούσε να είναι ένα σύστημα χημικής βιομηχανίας ή ένα
σύστημα διοίκησης παραγωγής κ.ο.κ.
Το σχήμα που ακολουθεί παρουσιάζει το διάγραμμα ενός συστήματος
κεντρικής θέρμανσης ενός σπιτιού. Το σπίτι έχει πέντε δωμάτια και το κάθε δωμάτιο έχει ένα
θερμαντικό σώμα (room radiator) το οποίο ελέγχεται από έναν θερμοστάτη. Ο κάθε θερμοστάτης μπορεί να
ελεγχθεί ξεχωριστά μέσω ρυθμιστή (knob). Οι ρυθμιστές είναι συνδεμένοι με τον κεντρικό
διακόπτη (central.switch) που δίνει εντολές και στον καυστήρα (boiler) του συστήματος κεντρικής
θέρμανσης. Το σύστημα σωλήνωσης (pipes) συνδέει τον καυστήρα με τα θερμαντικά σώματα στη σειρά, έτσι
ώστε δημιουργείται ένας δακτύλιος που καταλήγει πάλι στον καυστήρα. Η εξωτερική θερμοκρασία (ο
καιρός) διαδίδεται μέσω των παραθύρων κάθε δωματίου και γίνεται αντιληπτή από τον τοπικό
θερμοστάτη κάθε δωματίου. Τελικά φυσικά υπάρχει ο ανθρώπινος παράγοντας που έχει τον έλεγχο του
χρονοδιακόπτη και των θερμοστατών. Επιπλέον, στην προσομοίωση ο άνθρωπος γίνεται και λίγο
'θεός' καθορίζοντας τον καιρό.
Ο κώδικας του προγράμματος είναι ο ακόλουθος:
Program Susthma_Kentrikhs_Thermanshs; Const number_of_rooms=5; max_boil_temp=8500;min_boil_temp=500;boil_tmp_inc=100; max_temp=3500;min_temp=500;start_temp=550; max_setting=9;min_setting=0;start_setting=5; higher=1;lower=-1;incr=1; interval=10; margin=300;dissip=10;warm_up=15;size=5; sett_step=300; (*(max_temp-min_temp)div(max_setting-min_setting+1)*) off_heat=0;on_heat=1; false=0;true=1; forever = 32000; delay_const=1; Type chan=channel of integer; Pin= array[0..number_of_rooms] of chan; Var Boiler_Switch,Boiler_Control,God:chan; temp1,temp2:chan; Pipes:array[0..number_of_rooms+1] of chan; Knobs,Room_Windows:Pin; Switch,r:integer;
Η διεργασία αυτή είναι μια γεννήτρια τυχαίων αριθμών.
procedure random (r_x, r_n: real; var rnd: integer); const r_mod = 27296.0; r_mult = 4525.0; range = 10; offset = 3; var r_seed: real; x, n: integer; begin x := round(r_x + offset) mod range; n := round(r_n + offset) mod range; r_seed := x; r_seed := r_seed * r_mult; r_seed := r_seed / r_mod; rnd := round(n * r_seed) mod range; end;
Η διεργασία αυτή προκαλεί απλά καθυστέρηση- δε κάνει τίποτα.
procedure delay(times : integer); var i : integer; begin for i := 1 to times do end;
Η διεργασία που αρχικοποιεί την τιμή της heating;
Procedure init_switch(var heating:integer); begin heating:=false; end;
Η διεργασία heat_is_on εκτελείται όταν ανοίξουμε τον κεντρικό διακόπτη.
Procedure heat_is_on(var heating:integer;var start_heating:chan); begin if heating=false then begin heating:=true; start_heating:=true; end; end;
Αντίθετα η παρακάτω διεργασία εκτελείται όταν κλείσουμε τον κεντρικό διακόπτη.
Procedure heat_is_off(var heating:integer;var start_heating:chan); begin heating:=false; start_heating:=false; end;
Η διεργασία Central_Switch είναι η διεργασία κεντρικού διακόπτη, η οποία δέχεται εντολές από το χειριστή (άνθρωπο) μέσω του καναλιού on_off_switch το οποίο κανονίζει αν το σύστημα είναι ανοικτό ή κλειστό. Αντίστοιχα στέλνει εντολή στον καυστήρα μέσω του καναλιού start_heating.
Procedure Central_Switch(Var on_off_switch,start_heating:chan); Const off_heat=0;on_heat=1; Var switch,temp,heating:integer; begin while clock < forever do begin init_switch(heating); if on_off_switch? then begin switch:=on_off_switch; if switch=on_heat then heat_is_on(heating,start_heating) else if switch=off_heat then heat_is_off(heating,start_heating); end; end; end;
Αρχικοποίηση της θερμοκρασίας και της κατάστασης του boiler.
Procedure init_boiler(var boiler_on,heating,temp:integer); begin temp:=start_temp; boiler_on:=false; heating:=false; end;
Η διεργασία αυτή ελέγχει τον καυστήρα και ανάλογα τον θέτει η λειτουργία ή τον κλείνει, πράγμα που εξαρτάται από την επικοινωνία του με τον κεντρικό διακόπτη.
Procedure boil_contr(var on_signal,boiler_on,heating:integer); begin if (on_signal=true) and (heating=false) then begin boiler_on:=true; heating:=true; end else if (on_signal=false) and (heating=true) then begin boiler_on:=false; heating:=false; end; end;
Εδώ περιγράφεται η θέρμανση του νερού, όπου υπάρχουν τέσσερις καταστάσεις. Αν ο κεντρικός διακόπτης είναι ανοιχτός (heating = true) ο καυστήρας λειτουργεί ανεβάζονται βαθμιαία τη θερμοκρασία του νερού του κυκλώματος μέχρι να φτάσει στη μέγιστη θερμοκρασία (max_boil_temp). Όταν το νερό φθάσει τη μέγιστη θερμοκρασία ο καυστήρας σταματά (boiler_on = false) και το νερό κυκλοφορεί μέσα από τα ψυχρότερα στρώματα. Όταν η θερμοκρασία φτάσει στη ελάχιστη θερμοκρασία (min_boil_temp) τότε ο καυστήρας ανατίθεται ξανά σε λειτουργία. Φυσικά στην περίπτωση που ο κεντρικός διακόπτη είναι κλειστός τότε η θερμοκρασία του νερού παραμένει αμετάβλητη.
Procedure boiler_temp(temp: integer; var boiler_on, heating : integer; var initial_temp: chan); begin if (heating=true) and (boiler_on=true) then begin if (temp+boil_tmp_inc)>max_boil_temp then begin writeln('exei ftasei sthn anwterh thermokrasia-stamata proswrina'); boiler_on:=false; initial_temp:=max_boil_temp; end else begin initial_temp:=temp+boil_tmp_inc; writeln('h thermansh synexizetai'); writeln('h thermokrasia einai',temp+boil_tmp_inc); writeln; end; end else if (heating=true) and (boiler_on=false) then begin if temp < min_boil_temp then boiler_on:=true; writeln('exei ftasei sthn katwterh thermokrasia-arxizei th thermansh'); initial_temp:=temp; end else initial_temp:=temp; end;
Αυτή είναι η βασική διεργασία του καυστήρα, η οποία δέχεται είσοδο από τον κεντρικό διακόπτη, καθώς και από το σωλήνα που κλείνει το κύκλωμα των θερμαντικών σωμάτων.
Procedure Boiler(var control,initial_temp,final_temp:chan); Var on_signal,boiler_on,heating,temp:integer; begin init_boiler(boiler_on,heating,temp); while clock < forever do begin if control? then on_signal := control; while on_signal = true do begin if control? then on_signal := control; boil_contr(on_signal,boiler_on,heating); if final_temp? then temp := final_temp; boiler_temp(temp, boiler_on,heating,initial_temp); end; end; end;
Η διεργασία αρχικοποίησης των ρυθμίσεων του θερμοστάτη στα δωμάτια, καθώς και της θερμοκρασίας μέσα και έξω από το δωμάτιο:
Procedure init_room(var setting,room_temp,outside_temp,is_on:integer); begin setting:=start_setting; room_temp:=start_temp; outside_temp:=start_temp; is_on:=false; end;
Εδώ υλοποιείται η ρύθμιση της κλίμακας του θερμοστάτη με αυξομειώσεις κατά μια θέση της κλίμακας από 0 εώς 9.
Procedure adjust_knob(turn:integer;var setting:integer); begin if (turn=higher) and ((setting+incr)<=max_setting) then begin setting:=setting+incr; end else if (turn=lower) and ((setting-incr)>=min_setting) then begin setting:=setting-incr; end; end;
Στην διεργασία operation ελέγχεται σε τακτά διαστήματα (interval) η θερμοκρασία του δωματίου. Αν αυτή είναι χαμηλότερη από τη ρύθμιση του θερμοστάτη τότε το θερμαντικό σώμα αρχίζει και λειτουργεί. Το δωμάτιο θερμαίνεται ανάλογα με το μέγεθός του (size). Η θερμοκρασία του δωματίου αυξάνει μέχρι την επιθυμητή οπότε και σταματά να απορροφά νέα θερμοκρασία
Procedure operation(var room_temp,outside_temp,water_temp,is_on,setting:integer; var out:chan); var i,old_temp,gain,rnd:integer; begin random(clock,seqtime,rnd); for i:=1 to rnd do delay(delay_const); old_temp:=room_temp; room_temp:=room_temp+((outside_temp-room_temp) div dissip); if is_on=true then begin gain:=(water_temp-room_temp) div warm_up; out:=water_temp-gain; room_temp:=room_temp+((water_temp-room_temp) div size); if room_temp>((sett_step*setting)+min_temp+margin) then begin is_on:=false; end; end else begin out:=water_temp; if room_temp < (((sett_step*setting)+min_temp)-margin) then begin is_on:=true; end; end; end;
Η διεργασία του δωματίου αντιστοιχεί στο συνδυασμό του θερμαντικού σώματος με τον τοπικό θερμοστάτη και το ρυθμιστή του. Η διεργασία δέχεται τρεις εισόδους, δηλαδή τη θερμοκρασία του νερού που εισέρχεται στο θερμαντικό σώμα(water_temp), την εξωτερική θερμοκρασία του δωματίου (outside_temp) και την μεταβολή της ρύθμισης του θερμοστάτη (turn).
Procedure Room(n:integer;Var control_knob,in,out,outside:chan); var water_temp,turn,is_on,setting,room_temp,outside_temp:integer; begin init_room(setting,room_temp,outside_temp,is_on); while clock < forever do begin if control_knob? then begin turn:=control_knob; adjust_knob(turn,setting); end; water_temp:=in; operation(room_temp,outside_temp,water_temp,is_on,setting,out); end; end;
Έλεγχος του κεντρικού διακόπτη από το χειριστή:
Procedure control_interface(var heater:chan); var ch:char; begin writeln; writeln('dwse 1 gia na anoikseis to geniko diakopth kai 0 gia na ton kleiseis'); readln(ch); if ch='0' then heater:=off_heat else if ch='1' then heater:=on_heat else writeln('lathos eisodos'); end;
Έλεγχος των ρυθμιστών των θερμοστατών των δωματίων:
Procedure radiator_interface(var radiator_knobs:Pin); var n:integer; ch:char; begin writeln('dwse ton arithmo toy dwmatioy gia allagh toy thermostash'); writeln; readln(n); if (n>=0) and (n<=number_of_rooms) then begin writeln('dwse h gia anebasma toy thermostath kai l gia katebasma'); writeln; readln(ch); if ch='h' then radiator_knobs[n]:=higher else if ch='l' then radiator_knobs[n]:=lower else writeln('lathos eisodos'); end; end;
Προς χάριν της προσομοίωσης εδώ ο χειριστής ελέγχει και την εξωτερική θερμοκρασία.
Procedure weat_interface(var weather_chan:chan); var n:integer; begin writeln('dwse thn e3wterikh thermokrasia,metaksi -5 kai 45'); readln(n); if (n >(-5)) and (n ‹ 45) then weather_chan:=n*100 else writeln('lathos eisodos'); end;
Η διεργασία του χειριστή είναι ουσιαστικά η διεπαφή εισόδου του προγράμματος. Είναι ένα απλό σύστημα μενού που οδηγείται με τη πληκτρολόγηση χαρακτήρων ή αριθμών.
Procedure Human(Var heater:chan;Var radiator_knobs:Pin;Var weather_chan:chan); var ch:char; begin while ch < >'*' do begin writeln; writeln('dwse c gia elegxo kentrikoy diakopth,r gia elegxo twn rythmistwn'); writeln('twn thermostatwn twn dwmatiwn,w gia elegxo ths ekswterikhs thermokrasias'); writeln(' kai * gia termatismo'); writeln; readln(ch); if ch='c'then control_interface(heater) else if ch='r' then radiator_interface(radiator_knobs) else if ch='w' then weat_interface(weather_chan) else if ch='*' then writeln('dwsate tetrmatismo') else writeln('lathos eisodos'); end; end;
Αρχικοποίηση της θερμοκρασίας του καιρού.
Procedure init_weather(var new_temp:integer); begin new_temp:=start_temp; end;
Εδώ απλά η εξωτερική θερμοκρασία διαδίδεται προς όλα τα δωμάτια.
Procedure new_weather(new_temp:integer;var Windows:Pin); var r:integer; begin for r:=0 to number_of_rooms do Windows[r]:=new_temp; end;
Η κύρια διεργασία του καιρού:
Procedure Weather(Var Command:chan;Var Windows:Pin); var new_temp:integer; begin init_weather(new_temp); while clock < forever do begin if command? then begin new_temp := command; new_weather(new_temp,Windows); end; end; end; Procedure All_Rooms; Begin forall r:=0 to number_of_rooms do Room(r,Knobs[r],Pipes[r],Pipes[r+1],Room_Windows[r]); End;
Και το κυρίως πρόγραμμα :
Begin fork All_Rooms; fork Central_switch(Boiler_Switch,Boiler_Control); fork Boiler(Boiler_Control,Pipes[0],Pipes[number_of_rooms+1]); fork Human(Boiler_Switch,Knobs,God); fork Weather(God,Room_Windows); join;join;join;join;join; End.
Αυτό το πρόγραμμα κάθε χρήστης μπορεί να το εκτελέσει με πολλούς διαφορετικούς τρόπους, ανάλογα με τις επιλογές που θα κάνει στα μενού. Η έξοδος του προγράμματος είναι η θερμοκρασία του νερού, με την οποία καταλαβαίνουμε πότε δουλεύει ο καυστήρας και πότε όχι.
Επόμενο:ΠΑΡΑΛΛΗΛΗ ΤΑΞΙΝΟΜΗΣΗ Πάνω: Διάφορα Προβλήματα Παράλληλου Προγραμματισμού Πίσω: ΟΙ ΓΕΥΜΑΤΙΖΟΝΤΕΣ ΦΙΛΟΣΟΦΟΙ