ΠΛΕ-006 ΠΑΡΑΛΛΗΛΗ ΕΠΕΞΕΡΓΑΣΙΑ 2012-13 Project
Νήματα επιπέδου χρήστη (user-level threads)
Νήματα Επιπέδου Χρήστη Τα νήματα αυτά αποτελούνται από ένα περιγραφέα (descriptor) που περιέχει Τις τιμές των καταχωρητών του νήματος (registers, π.χ. τον program counter) Μια περιοχή μνήμης που χρησιμοποιείται ως στοίβα (stack) Τα νήματα επιπέδου χρήστη είναι οντότητες μη αναγνωρίσιμες από το λειτουργικό σύστημα Δημιουργούνται, διαχειρίζονται, χρονοδρομολογούνται και καταστρέφονται αποκλειστικά από τον χρήστη 3
Βασικές Ιδιότητες Νήματα επιπέδου πυρήνα (π.χ. POSIX threads) Υψηλός κόστος: οι πράξεις νημάτων είναι κλήσεις συστήματος Δρομολόγηση από το λειτουργικό σύστημα Εκμετάλλευση πολλών επεξεργαστών Αν ένα νήμα μπλοκάρει, τα υπόλοιπα νήματα συνεχίζουν την εκτέλεση τους Νήματα επιπέδου χρήστη Χαμηλό κόστος: οι πράξεις νημάτων είναι απλές κλήσεις συναρτήσεων Δρομολόγηση από τη βιβλιοθήκη, στο χρόνο εκτέλεσης της διεργασίας Δεν εκμεταλλεύονται πολλαπλούς επεξεργαστές Αν ένα νήμα μπλοκάρει, τότε μπλοκάρει όλη η διεργασία Κατηγορίες δρομολόγησης Χωρίς προεκχώρηση: με ελεγχόμενη εναλλαγή (π.χ. yield) Με προεκχώρηση: αυτόματη εναλλαγή, π.χ. με κάποιον timer 4
Μηχανισμοί για υλοποίηση νημάτων χρήστη Μηχανισμοί υλοποίησης μη-μεταφέρσιμοι (assembly) ημι-μεταφέρσιμοι (setjmp/longjmp) ucontext_t operations (makecontext, swapcontext) 5
setjmp - longjmp #include <setjmp.h> jmpbuf context; int setjmp(jmp_buf env); Αποθηκεύει το context στον buffer env και επιστρέφει 0 Όταν αποκατασταθεί το context (από τη longjmp()), θα συνεχίσει η εκτέλεση από το ίδιο σηµείο. Τότε η setjmp() επιστρέφει την τιµή του ορίσματος val της longjmp(). void longjmp(jmp_buf env, int val); Αποκαθιστά το context που έχει αποθηκευτεί στον buffer env από προηγούμενη κλήση της setjmp() Αν val==0 τότε η setjmp επιστρέφει 1 Αν val!=0 τότε η setjmp επιστρέφει val 6
setjmp - longjmp #include<setjmp.h> #include<stdio.h> int main(void) int value; jmp_buf environment_buffer; value=setjmp(environment_buffer); if(value!=0) printf("reached this point with value=%d.\n",value); exit(0); printf("calling function.\n"); some_function(environment_buffer); return 0; void some_function(jmp_buf env_buf) longjmp(env_buf,5); 7
setjmp - longjmp Χρήση για εναλλαγή από old_thread σε new_thread switch(old_thread, new_thread) if (setjmp(old_thread->context)!= 0) longjmp(new_thread->context, 1); /* δεν επιστρέφει ποτέ εδώ*/ /* εδώ θα επιστρέψει η εκτέλεση του οld_thread μετά από µία κλήση της συνάρτησης longjmp(old_thread->context, 1); */ old_thread_work(); 8
makecontext -swapcontext #include <ucontext.h> ucontext_t context; Πεδία δομής (μερικά): stack_t uc_stack: Η στοίβα που χρησιμοποιείται από το context ucontext_t uc_mcontext: αναπαράσταση ενός context που έχει σωθεί Κλήσεις int getcontext(ucontext_t *ucp); int setcontext(const ucontext_t *ucp); void makecontext(ucontext_t *ucp, (void *f)(),int argc,...); int swapcontext(ucontext_t *oucp, const ucontext_t *ucp); 9
makecontext -swapcontext #include <ucontext.h> ucontext_t auc,buc,mainuc; int main(void) printf("start\n"); /* Set up context for thread A */ getcontext(&auc); auc.uc_stack.ss_size = 16 * 1024; auc.uc_stack.ss_sp = malloc(auc.uc_stack.ss_size); makecontext(&auc, a, 0); void a() int i; for (i = 0; i < 10; i++) printf("a"); swapcontext(&auc, &buc); /* switch to thread B */ printf("\nswitching to main\n"); swapcontext(&auc, &mainuc); /* switch to main thread */ void b() int i; /* Set up context for thread B */ getcontext(&buc); buc.uc_stack.ss_size = 16 * 1024; buc.uc_stack.ss_sp = malloc(buc.uc_stack.ss_size); makecontext(&buc, b, 0); for (i = 0; i < 10; i++) printf("b"); swapcontext(&buc, &auc); /* switch to thread A */ /* Switch to A */ getcontext(&mainuc); /* Save the context of main thread */ swapcontext(&mainuc, &auc); /* Switch to thread A */ printf("done\n"); /* Execution control returned to main thread */ return 0; 10
A simple user-level threads facility #include <ucontext.h> ucontext_t context_create(void (*func)(void *), void *arg) ucontext_t *uc = malloc(sizeof(ucontext_t)); getcontext(uc); /* A copy of current context */ uc->uc_stack.ss_size = 65536; /* Change its values */ uc->uc_stack.ss_sp = malloc(65536); makecontext(uc, func, 1, arg); /* Ready to use */ return (uc); void context_switch(ucontext_t *from, ucontext_t *to) if (from!= NULL) swapcontext(from, to); /* Save current in from */ else setcontext(to); /* Current context is lost */ What happens at thread_exit()? /* There is a ready queue of threads */ thread_create(void (*func)(void *), void *arg) <enqueue>( context_create(func, arg) ); scheduler() ucontext_t *uc = <dequeue>(); /* FIFO */ context_switch(current_uc, uc); thread_exit() <must delete thread s stuff (e.g. stack)> scheduler(); /* Run another thread */ thread_yield() scheduler(); /* Run another thread */ thread_join(...) What if the thread function simply returns (i.e. does not call thread_exit())? 11
PROJECT ithreads
ithreads Υλοποίηση ioannina -threads Νήματα επιπέδου χρήστη Βιβλιοθήκη που μπορεί να χρησιμοποιηθεί από οποιονδήποτε Μεταφέρσιμη (με χρήση ucontext) Αρχικά σε έναν επεξεργαστή, στη συνέχεια σε περισσότερους Μηχανισμοί δημιουργίας, δρομολόγησης νημάτων Μηχανισμοί αμοιβαίου αποκλεισμού Μηχανισμοί συγχρονισμού 13 ΠΛΕ-006 Παράλληλη Επεξεργασία
Φάση 1 η Αρχική έκδοση, δημιουργία και δρομολόγηση νημάτων σε 1 επεξεργαστή Υλοποίηση μηχανισμού με περιβάλλοντα εκτέλεσης low.c με χρήση του ucontext Χρήση του μηχανισμού low για αρχική έκδοση της βιβλιοθήκης ithreads: ithr_init() ithr_thread_new() ithr_exit() ithr_yield() 14 ΠΛΕ-006 Παράλληλη Επεξεργασία
Φάση 1 η 2 αρχεία C, το καθένα με δικό του Interface (.h) Makefile, βιβλιοθήκη (ar) -> libithr.a Ο σκελετός των αρχείων δίνεται Δοκιμαστικά αρχεία δικά σας και του διδάσκοντα Link με τη βιβλιοθήκη ithr Dates: 13/11: progress report 20/11: παράδοση 15 ΠΛΕ-006 Παράλληλη Επεξεργασία