CSLab National Technical University of Athens

Σχετικά έγγραφα
Μηχανισμοί και προγραμματιστικές δομές συγχρονισμού. Προβλήματα συγχρονισμού (και λύσεις)

Συγχρονισμός. Συστήματα Παράλληλης Επεξεργασίας 9ο εξάμηνο ΣΗΜΜΥ ακ. έτος CSLab. Κορνήλιος Κούρτης

Λειτουργικά Συστήματα

Λειτουργικά Συστήματα

Εργαστήριο 4: Υλοποίηση Αφηρημένου Τύπου Δεδομένων: Ταξινομημένη Λίστα

ΛΕΙΤΟΥΡΓΙΚΑ ΣΥΣΤΗΜΑΤΑ. Διαδιεργασιακή Επικοινωνία Εργαστηριακές Ασκήσεις

Συγχρονισμός Μέρος Α : Κρίσιμο τμήμα και κλειδώματα

Επικοινωνία µεταξύ ιεργασιών και Σύνδροµες ιεργασίες

Διάλεξη 12: Λίστες Υλοποίηση & Εφαρμογές. Διδάσκων: Παναγιώτης Ανδρέου

ΛΕΙΤΟΥΡΓΙΚΑ ΣΥΣΤΗΜΑΤΑ ΔΙΑΔΙΕΡΓΑΣΙΑΚΗ ΕΠΙΚΟΙΝΩΝΙΑ ΣΥΓΧΡΟΝΙΣΜΟΣ

Γράφοι. Ορολογία. Ορισµός: G = (V, E) όπου. Ορολογία (συνέχεια) γράφος ή γράφηµα (graph) V:ένα σύνολο E:µια διµελής σχέση στο V

ΣυγχρονισµόςσεΣυστήµατα ΠολλαπλώνΝηµάτων

ΠΛΗ111. Ανοιξη Μάθηµα 5 ο. Ουρά. Τµήµα Ηλεκτρονικών Μηχανικών και Μηχανικών Υπολογιστών Πολυτεχνείο Κρήτης

Διάλεξη 13: Δομές Δεδομένων ΙΙ (Ταξινομημένες Λίστες)

Λειτουργικά Συστήματα Η/Υ

Διδάσκων: Κωνσταντίνος Κώστα Διαφάνειες: Δημήτρης Ζεϊναλιπούρ

Διάλεξη 14: Δομές Δεδομένων ΙΙI (Λίστες και Παραδείγματα)

2.4 Κλασσικά Προβλήματα IPC

Σι θα δούμε σε αυτό το μάθημα;

Συγχρονισμός. Εθνικό Μετσόβιο Πολυτεχνείο Σχολή Ηλεκτρολόγων Μηχ. και Μηχανικών Υπολογιστών Εργαστήριο Υπολογιστικών Συστημάτων

Ενότητα 4 (Κεφάλαιο 5) Συντρέχων Προγραμματισμός

ΠΛΗ111. Ανοιξη Μάθηµα 4 ο. Στοίβα. Τµήµα Ηλεκτρονικών Μηχανικών και Μηχανικών Υπολογιστών Πολυτεχνείο Κρήτης

Dr. Garmpis Aristogiannis - EPDO TEI Messolonghi

Λειτουργικά Συστήματα

Ελεγκτές/Παρακολουθητές (Monitors) Ταυτόχρονος Προγραμματισμός 1

Συγχρονισμός. Εθνικό Μετσόβιο Πολυτεχνείο Σχολή Ηλεκτρολόγων Μηχ. και Μηχανικών Υπολογιστών Εργαστήριο Υπολογιστικών Συστημάτων

Συγχρονισμός. Εθνικό Μετσόβιο Πολυτεχνείο Σχολή Ηλεκτρολόγων Μηχ. και Μηχανικών Υπολογιστών Εργαστήριο Υπολογιστικών Συστημάτων

Υλοποίηση Λιστών. Στην ενότητα αυτή θα μελετηθούν τα εξής επιμέρους θέματα:

ιαφάνειες παρουσίασης #6 (α)

ΠΑΝΕΠΙΣΤΗΜΙΟ ΚΥΠΡΟΥ ΤΜΗΜΑ ΠΛΗΡΟΦΟΡΙΚΗΣ

Δομές Δεδομένων. Ενότητα 10: Πλήρη Δυαδικά Δέντρα, Μέγιστα/Ελάχιστα Δέντρα & Εισαγωγή στο Σωρό- Ο ΑΤΔ Μέγιστος Σωρός. Καθηγήτρια Μαρία Σατρατζέμη

2.3 Επικοινωνία Διεργασιών

Ιδιοκτησία Αντικειµένου

Λειτουργικά Συστήματα

Στοίβες - Ουρές. Στοίβα (stack) Γιάννης Θεοδωρίδης, Νίκος Πελέκης, Άγγελος Πικράκης Τµήµα Πληροφορικής

ΤΕΧΝΙΚΕΣ ΑΝΤΙΚΕΙΜΕΝΟΣΤΡΑΦΟΥΣ ΠΡΟΓΡΑΜΜΑΤΙΣΜΟΥ. Εισαγωγή στη Java

Φροντιστήριο 4 Σκελετοί Λύσεων

Προσπέλαση σύνθετων δομών δεδομένων χωρίς καθολικό κλείδωμα

Λειτουργικά Συστήματα 7ο εξάμηνο, Ακαδημαϊκό Έτος

Προσπέλαση σύνθετων δομών δεδομένων χωρίς καθολικό κλείδωμα

Εργαστήριο 5: Υλοποίηση Αφηρημένου Τύπου Δεδομένων: Διπλά Συνδεδεμένη Λίστα

Λειτουργικά Συστήματα

Προβλήματα Συγχρονισμού (με ελεγκτή) Ταυτόχρονος Προγραμματισμός 1

Νήµατα Εκτέλεσης Συγχρονισµός ιεργασιών σε Κοινή Μνήµη

ENOTHTA 3 ΣYNTPEXΩN ΠPOΓPAMMATIΣMOΣ

ΕΛΛΗΝΙΚΗ ΕΤΑΙΡΕΙΑ ΕΠΙΣΤΗΜΟΝΩΝ ΚΑΙ ΕΠΑΓΓΕΛΜΑΤΙΩΝ ΠΛΗΡΟΦΟΡΙΚΗΣ ΚΑΙ ΕΠΙΚΟΙΝΩΝΙΩΝ ΜΕΛΟΣ IFIP, IOI

Σειρά Προβλημάτων 1 Λύσεις

ΕΡΓΑΣΤΗΡΙΟ 5 ΣΗΜΕΙΩΣΕΙΣ

ΠΛΗ111. Ανοιξη Μάθηµα 3 ο. Συνδεδεµένες Λίστες. Τµήµα Ηλεκτρονικών Μηχανικών και Μηχανικών Υπολογιστών Πολυτεχνείο Κρήτης

Δομές Δεδομένων & Αλγόριθμοι

Λειτουργικά Συστήματα (ΗΥ222)

Λειτουργικά Συστήματα 7ο εξάμηνο, Ακαδημαϊκό Έτος

Οντοκεντρικός Προγραμματισμός

ΤΕΧΝΙΚΕΣ ΑΝΤΙΚΕΙΜΕΝΟΣΤΡΑΦΟΥΣ ΠΡΟΓΡΑΜΜΑΤΙΣΜΟΥ. Εισαγωγή στη Java II

Υπολογισμός - Εντολές Επανάληψης

Λειτουργικά Συστήματα

Προβλήματα Συγχρονισμού (με ελεγκτή) Ταυτόχρονος Προγραμματισμός 1

υναµικές οµές εδοµένων (συν.) Στην ενότητα αυτή θα µελετηθούν τα εξής επιµέρους θέµατα:

Προγραμματισμός Ι (ΗΥ120)

Δομές Δεδομένων. Ενότητα 6: Εφαρμογή Συνδεδεμένων Λιστών: Αλφαβητικό ευρετήριο κειμένου- Υλοποίηση ΑΤΔ Στοίβα και Ουρά με δείκτες

Παράλληλη Επεξεργασία Κεφάλαιο 10 ο Αντίγραφα Εργαζομένων

ΔΟΜΕΣ ΔΕΔΟΜΕΝΩΝ & ΑΛΓΟΡΙΘΜΟΙ ΕΡΓΑΣΤΗΡΙΟ

Προγραμματισμός Ι. Δομές Δεδομένων. Δημήτρης Μιχαήλ. Ακ. Έτος Τμήμα Πληροφορικής και Τηλεματικής Χαροκόπειο Πανεπιστήμιο

Διάλεξη 21η: Απλά Συνδεδεμένες Λίστες

Ειδικά Θέματα Ι. Σήμερα!

ΤΕΧΝΙΚΕΣ ΑΝΤΙΚΕΙΜΕΝΟΣΤΡΑΦΟΥΣ ΠΡΟΓΡΑΜΜΑΤΙΣΜΟΥ. Εισαγωγή στη Java II

Ανάπτυξη Μεγάλων Εφαρµογών στη Γλώσσα C (2)

ΤΕΧΝΙΚΕΣ ΑΝΤΙΚΕΙΜΕΝΟΣΤΡΑΦΟΥΣ ΠΡΟΓΡΑΜΜΑΤΙΣΜΟΥ. Εισαγωγή στη Java

Σημειώσεις ένατης εβδομάδας

Προχωρημένα Θέματα ΠΡΟΧΩΡΗΜΕΝΑ ΘΕΜΑΤΑ. Γεώργιος Παπαϊωάννου ( )

Εικονική Μνήμη (Virtual Memory) Προγραμματισμός II 1

Δομές Δεδομένων. Καθηγήτρια Μαρία Σατρατζέμη. Τμήμα Εφαρμοσμένης Πληροφορικής. Δομές Δεδομένων. Τμήμα Εφαρμοσμένης Πληροφορικής

Goals of this Lecture. Generics(Γενικότητα) Generic Data Structures Example. Generic Data Structures Example

Διάλεξη 15: Δομές Δεδομένων IV (Διπλά Συνδεδεμένες Λίστες)

ΕΘΝΙΚΟ ΚΑΙ ΚΑΠΟΔΙΣΤΡΙΑΚΟ ΠΑΝΕΠΙΣΤΗΜΙΟ ΑΘΗΝΩΝ ΤΜΗΜΑ ΠΛΗΡΟΦΟΡΙΚΗΣ & ΤΗΛΕΠΙΚΟΙΝΩΝΙΩΝ ΧΕΙΜΕΡΙΝΟ ΕΞΑΜΗΝΟ ΜΑΘΗΜΑ: ΛΕΙΤΟΥΡΓΙΚΑ ΣΥΣΤΗΜΑΤΑ

Δομές Δεδομένων. Ενότητα 3: Ουρές Εισαγωγή-Υλοποίηση ΑΤΔ Ουρά με πίνακα. Καθηγήτρια Μαρία Σατρατζέμη. Τμήμα Εφαρμοσμένης Πληροφορικής.

ΛΙΣΤΕΣ. Ορισμός ΑΤΔ Λίστα ΑΤΔ Ακολουθιακή Λίστα Διαχείριση Δεικτών και Λιστών στη C ΑΤΔ Συνδεδεμένη Λίστα. Εφαρμογές και Χρήση Λιστών

ΠΛΗΡΟΦΟΡΙΚΗ ΙΙ (JAVA) 11/3/2008

Η γλώσσα προγραμματισμού C Συνδεδεμένες Λίστες

Ελεγκτές/Παρακολουθητές (Monitors) Ταυτόχρονος Προγραμματισμός 1

Εισαγωγή στον Προγραμματισμό

ΠΛΗ111. Ανοιξη Μάθηµα 8 ο. Αναζήτηση. Τµήµα Ηλεκτρονικών Μηχανικών και Μηχανικών Υπολογιστών Πολυτεχνείο Κρήτης

Δομές ελέγχου ροής προγράμματος

ΝΗΜΑΤΑ - ΕΡΓΑΣΤΗΡΙΟ 1 - ΣΗΜΕΙΩΣΕΙΣ

Ε-85: Ειδικά Θέµατα Λογισµικού

Διάλεξη 07: Λίστες Ι Υλοποίηση & Εφαρμογές

ΕΠΛ 034: Εισαγωγή στον Προγραμματισμό για ΗΜΥ

Δομές Δεδομένων. Ενότητα 4: Ο ΑΤΔ Λίστα & Υλοποίηση Λίστας με σειριακή αποθήκευση- Ο ΑΤΔ Συνδεδεμένη Λίστα- Υλοποίηση ΑΤΔ Συνδεδεμένη Λίστα με πίνακα

Εικονική Μνήμη (Virtual Memory) Προγραμματισμός II 1

ΛΕΙΤΟΥΡΓΙΚΑ ΣΥΣΤΗΜΑΤΑ Ι. Κεφάλαιο 2ο: Διεργασίες

Εισαγωγή. Η Occam είναι µια παράλληλη γλώσσα. που αναπτύχθηκε στη Μεγάλη Βρετανία.

υναµική έσµευση Μνήµης (συν.) ΕΠΛ 132 Αρχές Προγραµµατισµού ΙΙ 2 Εφαρµογή

Αμοιβαίος αποκλεισμός με κοινή μνήμη. Ταυτόχρονος Προγραμματισμός 1

Σύνοψη Προηγούμενου (1/2) Στοίβες, Ουρές, Ουρές Προτεραιότητας. Σύνοψη Προηγούμενου (2/2) Σημερινό Μάθημα. Πίνακες. Εισαγωγή, σε χρόνο O(1).

Δομές Δεδομένων. Ενότητα 1: Εισαγωγή-Υλοποίηση του ΑΤΔ Σύνολο με Πίνακα. Καθηγήτρια Μαρία Σατρατζέμη. Τμήμα Εφαρμοσμένης Πληροφορικής.

Alternative to Balanced Trees, Comms of the ACM, 33(6), June 1990,

ΑΣΚΗΣΕΙΣ ΓΙΑ ΤΟ ΕΡΓΑΣΤΗΡΙΟ 2

Εισαγωγή στους Αλγορίθμους

ΤΕΧΝΟΛΟΓΙΑ ΚΑΙ ΠΡΟΓΡΑΜΜΑΤΙΣΜΟΣ ΥΠΟΛΟΓΙΣΤΩΝ ΠΑΝΕΠΙΣΤΗΜΙΟ ΠΑΤΡΩΝ ΠΟΛΥΤΕΧΝΙΚΗ ΣΧΟΛΗ ΤΜΗΜΑ ΜΗΧΑΝΙΚΩΝ Η/Υ ΚΑΙ ΠΛΗΡΟΦΟΡΙΚΗΣ

ΑΡΧΕΣ ΠΡΟΓΡΑΜΜΑΤΙΣΜΟΥ

Transcript:

http://www.cslab.ece.ntua.gr/courses/os CSLab National Technical University of Athens

#define NEXT(x) ((x + 1) % N) item_t buffer[n]; int in=0, out=0, count=0;

#define NEXT(x) ((x + 1) % N) item_t buffer[n]; int in=0, out=0, count=0; void enqueue(item_t item){ item_t item; item_t dequeue(void){ item_t item; buffer[in] = item; in = NEXT(in); count++; item = buffer[out]; out = NEXT(out); count--; return item

#define NEXT(x) ((x + 1) % N) item_t buffer[n]; int in=0, out=0, count=0; void enqueue(item_t item){ item_t item; while (count == N) ; // wait buffer[in] = item; in = NEXT(in); count++; item_t dequeue(void){ item_t item; while (count == 0) ; // wait item = buffer[out]; out = NEXT(out); count--; return item

#define NEXT(x) ((x + 1) % N) item_t buffer[n]; int in=0, out=0, count=0; void enqueue(item_t item){ item_t item; while (count == N) ; // wait buffer[in] = item; in = NEXT(in); count++; item_t dequeue(void){ item_t item; while (count == 0) ; // wait item = buffer[out]; out = NEXT(out); count--; return item

count++ count--

count++ count-- = 0 = = 7 = 1

struct list_head { struct list_head *next; struct list_head *prev; ; list_del(prev, next) { prev->next = next; next->prev = prev;

struct list_head { struct list_head *next; struct list_head *prev; ; list_del(prev, next) { prev->next = next; next->prev = prev; t0: prev->next = next; t0: next->prev = prev;

struct list_head { struct list_head *next; struct list_head *prev; ; list_del(prev, next) { prev->next = next; next->prev = prev; t0: prev->next = next; t1: prev->next = next;

struct list_head { struct list_head *next; struct list_head *prev; ; list_del(prev, next) { prev->next = next; next->prev = prev; t0: prev->next = next; t1: prev->next = next;

p0-ins0 p0-ins1 p0-ins2... p1-ins0 p1-ins1 p1-ins2... p2-ins0 p2-ins1 p2-ins2... p2-ins0 p2-ins1 p0-ins0 p1-ins0...

p0-ins0 p0-ins1 p0-ins2... p1-ins0 p1-ins1 p1-ins2... p2-ins0 p2-ins1 p2-ins2...

do { lock(mylock); /* critical section */ code unlock(mylock); remainder section while (TRUE);

do { do { lock(mylock); lock(mylock); /* critical section */ /* critical section */ code other code unlock(mylock); unlock(mylock); remainder section other remainder section while (TRUE); while (TRUE);

bool flag[2] = { FALSE, FALSE ; do { flag[me] = TRUE; while (flag[other]) ; critical section flag[me] = FALSE; remainder section while (TRUE);

bool flag[2] = { FALSE, FALSE ; do { flag[me] = TRUE; while (flag[other]) ; critical section flag[me] = FALSE; remainder section while (TRUE); me=0 me=1

bool flag[2] = { FALSE, FALSE ; do { flag[me] = TRUE; while (flag[other]) ; critical section flag[me] = FALSE; remainder section while (TRUE); me=0 me=1

do { flag[me] = TRUE; turn = other; while (flag[other] && turn == other) ; critical section flag[me] = FALSE; remainder section while (TRUE);

TestAndSet Swap

do { while (TestAndSet(lock)) ; critical section UnSet(lock); remainder section while (TRUE);

do { while (TestAndSet(lock)) ; critical section UnSet(lock); remainder section while (TRUE); do { key = TRUE; while (key) Swap(lock,key); critical section UnSet(lock); remainder section while (TRUE);

do { while (TestAndSet(lock)) ; critical section UnSet(lock); remainder section while (TRUE); do { key = TRUE; while (key) Swap(lock,key); critical section UnSet(lock); remainder section while (TRUE);

#define NEXT(x) ((x + 1) % N) bool waiting[n], lock, key; Lock: Set(waiting[me]); key = TRUE; while ((Test(waiting[me]) && key) key = TestAndSet(&lock); UnSet(waiting[me]); Unlock: for (j = NEXT(me); ; j = NEXT(j)){ if (j == me){ UnSet(lock); break; if (Test(waiting[j])){ UnSet(waiting[j]); break;

wait signal wait() signal() wait() signal()

wait (S) { while (S <= 0) ; S--; signal (S) { S++;

wait (S) { while (S <= 0) ; S--; signal (S) { S++;

wait (S) { while (1) { lock(s_lock); if (S > 0) { S--; unlock(s_lock); break; unlock(s_lock); signal (S) { lock(s_lock); S++; unlock(s_lock);

typedef struct { int value; lock s_lock; struct process *list; Semaphore; wait (Semaphore *S) { lock(s->s_lock); S->value--; if (S->value < 0) { add proc to S->list; unlock(s->s_lock); block(); unlock(s->s_lock); signal (Semaphore *S) { lock(s->s_lock); S->value++; if (S->value <= 0) { remove P from S->list; wakeup(p); unlock(s->s_lock);

wait() signal() 1

1 1 2 2 sema // P1 S1(); signal(sema); // P2 wait(sema); S2();

#define NEXT(x) ((x + 1) % N) item_t buffer[n]; int in=0, out=0, count=0; void enqueue(item_t item){ item_t item; while (count == N) ; // wait buffer[in] = item; in = NEXT(in); count++; item_t dequeue(void){ item_t item; while (count == 0) ; // wait item = buffer[out]; out = NEXT(out); count--; return item

#define NEXT(x) ((x + 1) % N) item_t buffer[n]; int in=0, out=0, count=0; sema_t mutex = semaphore(1); void enqueue(item_t item){ wait(mutex); item_t item; while (count == N) ; // wait buffer[in] = item; in = NEXT(in); count++; signal(mutex); item_t dequeue(void){ wait(mutex); item_t item; while (count == 0) ; // wait item = buffer[out]; out = NEXT(out); count--; signal(mutex); return item

#define NEXT(x) ((x + 1) % N) item_t buffer[n]; int in=0, out=0, count=0; sema_t mutex = semaphore(1); void enqueue(item_t item){ wait(mutex); item_t item; while (count == N) ; // wait buffer[in] = item; in = NEXT(in); count++; signal(mutex); item_t dequeue(void){ wait(mutex); item_t item; while (count == 0) ; // wait item = buffer[out]; out = NEXT(out); count--; signal(mutex); return item

#define NEXT(x) ((x + 1) % N) item_t buffer[n]; int in=0, out=0, count=0; sema_t mutex = semaphore(1); sema_t items = semaphore(0); sema_t space = semaphore(n); void enqueue(item_t item){ item_t item; item_t dequeue(void){ item_t item; buffer[in] = item; in = NEXT(in); count++; item = buffer[out]; out = NEXT(out); count--; return item

#define NEXT(x) ((x + 1) % N) item_t buffer[n]; int in=0, out=0, count=0; sema_t mutex = semaphore(1); sema_t items = semaphore(0); sema_t space = semaphore(n); void enqueue(item_t item){ item_t item; wait(space); wait(mutex); buffer[in] = item; in = NEXT(in); count++; signal(mutex); signal(items); item_t dequeue(void){ item_t item; wait(items); wait(mutex); item = buffer[out]; out = NEXT(out); count--; signal(mutex); signal(space); return item

sema_t mutex = semaphore(1); sema_t write = semaphore(1); int readcount = 0; read_lock: wait(mutex); if (++readcount == 1) wait(write); signal(mutex); write_lock: wait(write); write_unlock: signal(write); read_unlock: wait(mutex); if (--readcount == 0) signal(write); signal(mutex);

P1 P5 P2 P4 P3

#define NEXT(x) ((x+1) % N) sema_t F[N]; //forks do { think(); wait(f[i]); wait(f[next(i)]); eat(); signal(f[next(i)]); signal(f[i]); while (TRUE); P5 P1 P2 P4 P3

#define NEXT(x) ((x+1) % N) sema_t F[N]; //forks do { think(); wait(f[i]); wait(f[next(i)]); eat(); signal(f[next(i)]); signal(f[i]); while (TRUE); P5 P1 P2 P4 P3

#define NEXT(x) ((x+1) % N) sema_t F[N]; //forks do { think(); wait(f[i]); wait(f[next(i)]); eat(); signal(f[next(i)]); signal(f[i]); while (TRUE); P5 L W L P1 W L W P2 W P4 L W P3 L

P1 P5 P2 P4 P3

4 5 P5 P1 P2 P4 P3

4 5 P5 P1 P2 P4 P3

monitor MyMonitor { // shared variables int a; // methods procedure P_1(...) {... procedure P_2(...) {... // initialization initialize() { a =......

#define NEXT(x) ((x + 1) % N) monitor ProducerConsumer { // end ProducerConsumer

#define NEXT(x) ((x + 1) % N) monitor ProducerConsumer { item_t buffer[n]; int in=0, out=0, count=0; condition full, empty; void enqueue(item_t item){ item_t dequeue(void){ // end ProducerConsumer

#define NEXT(x) ((x + 1) % N) monitor ProducerConsumer { item_t buffer[n]; int in=0, out=0, count=0; condition full, empty; void enqueue(item_t item){ item_t item; if (count == N) full.wait(); buffer[in] = item; in = NEXT(in); if (++count == 1) empty.signal(); // end ProducerConsumer item_t dequeue(void){

#define NEXT(x) ((x + 1) % N) monitor ProducerConsumer { item_t buffer[n]; int in=0, out=0, count=0; condition full, empty; void enqueue(item_t item){ item_t item; if (count == N) full.wait(); buffer[in] = item; in = NEXT(in); if (++count == 1) empty.signal(); // end ProducerConsumer item_t dequeue(void){ item_t item; if (count == 0) empty.wait(); item = buffer[out]; out = NEXT(out); if (count-- == N) full.signal(); return item;

monitor DiningPhilosophers { enum {T, H, E state[5]; condition cond[n]; void pickup(int i) { void putdown(int i) { state[i] = H; state[i] = T; test(i); test(prev(i)); if (state[i]!= E) test(next(i)); cond[i].wait(); void test(int i){ if (state[i] == H && state[prev(i)]!= E && state[next(i)]!= E){ state[i] = E; cond[i].signal(); // end of DiningPhilosophers

Π

Π

Π

Π

1 2... 1 1

Π 1 Π 3 Π Π Π 1 2 3 Π 2 Π 4

Π 1 Π 3 Π Π Π 1 2 3 Π 2 Π 4

Π 1 Π 3 Π Π Π 1 2 3 Π 2 Π 4