180 likes | 295 Views
ΛΕΙΤΟΥΡΓΙΚΑ ΣΥΣΤΗ M ΑΤΑ Ι. NIKO ΛΑΟΣ ΝΤΙΡΛΗΣ 5 ο ΦΡΟΝΤΙΣΤΗΡΙΟ ΑΙΘΟΥΣΑ Β4. Processes Vs Threads! (1/3). Ένα thread έχει : ID, program counter, register set, stack
E N D
ΛΕΙΤΟΥΡΓΙΚΑ ΣΥΣΤΗMΑΤΑ Ι NIKOΛΑΟΣ ΝΤΙΡΛΗΣ 5ο ΦΡΟΝΤΙΣΤΗΡΙΟ ΑΙΘΟΥΣΑ Β4
Processes Vs Threads! (1/3) Ένα thread έχει: ID, program counter, register set, stack Μοιράζεται με τα άλλα threads της ίδιας διεργασίαςτον κώδικα, τα δεδομένα και τους άλλους πόρους που του έχουν διατεθεί από το ΛΣ (σήματα, αρχεία κτλ)
Processes Vs Threads! (2/3) Πλεονεκτήματα των νημάτων σε σχέση με τις διεργασίες: Όταν μια process είναι blocked, τίποτα δεν τρέχει. Όταν ένα thread είναι blocked, τα άλλα threads της ίδιας process εκτελούνται. Δημιουργία και τερματισμός threads είναι πολύ πιο οικονομικός από τις αντίστοιχες ενέργειες πάνω σε processes. Αυτό συμβαίνει κυρίως γιατί τα threads μιας διεργασίας μοιράζονται το ίδιο address space.
Processes Vs Threads! (3/3) Switch time ανάμεσα σε δύο threads είναι πολύ πιο μικρός Communication time πολύ πιο μικρός. Αξιοποίηση δυνατοτήτων σύγχρονων αρχιτεκτονικών (πχ Intel Hyper-Threading processors)
POSIX Threads library POSIX Threads library: pthread.h μας δίνει δυνατότητες να: Δημιουργούμε και καταστρέφουμε threads Passing messages and data between threads Scheduling thread execution Saving and restoring thread contexts
Συγχρονισμός Threads Η POSIX Threads library μας παρέχει τρεις μηχανισμούς συγχρονισμού: mutexes - Mutual exclusion lock: Block access to variables by other threads. This enforces exclusive access by a thread to a variable or set of variables. joins - Make a thread wait till others are complete (terminated). condition variables - data type pthread_cond_t
Νήματα – αμοιβαίος αποκλεισμός • Θέματα παραλληλίας • Όταν δημιουργούμε ένα νέο νήμα (thread) και τα δύο νήματα χρησιμοποιούν την ίδια μνήμη • Αν το νέο νήμα κάνει κάποια αλλαγή στις μεταβλητές (π.χ., διαχείριση παραγγελίας) τότε αυτή η αλλαγή ενδεχομένως επηρεάζει άλλα νήματα • Αν δύο νήματα θέλουν να αλλάξουν την ίδια μεταβλητή (π.χ., καταχώρηση νέας κράτησης) τι γίνεται ? • Αυτό δημιουργεί θέματα αμοιβαίου αποκλεισμού -- mutex
Δημιουργία νημάτων • Αρχικά η συνάρτηση main δημιουργεί το κεντρικό νήμα • Όλα τα υπόλοιπα νήματα πρέπει να δημιουργηθούν κατά την εκτέλεση
pthread_create: Δημιουργία νήματος • Αντίστοιχη της fork() για το process • Η συνάρτηση pthread_create έχει τις ακόλουθες παραμέτρους • Ταυτότητα (αριθμός) νήματος – τιμή που επιστρέφει η συνάρτηση • Παράμετροι νήματος – attributes, NULL για προκαθορισμένες παραμέτρους • Συνάρτηση εκκίνησης – η συνάρτηση που θα εκτελεστεί μόλιςδημιουργηθεί το νέο νήμα • Παράμετροι συνάρτησης – οι μεταβλητές που θα περαστούν στηνσυνάρτηση μόλις εκτελεστεί
Δημιουργία νημάτων: intpthread_create( pthread\_t *tid, const pthread\_attr\_t *tattr,void*(*start_routine)(void *), void *arg ); Όταν ένα όρισμα δεν συγκεκριμενοποιείται τότε παίρνει την default τιμή. Με την pthread_attr_init() μπορείτε να ορίσετε αυτές τις default τιμές. Start_routine είναι η συνάρτηση που θα εκτελεστεί μόλις δημιουργηθεί το νήμα και arg οι παράμετροι που θα περάσουμε σε αυτή τη συνάρτηση. pthread_self()- return identifier of current thread
pthread_create: Δημιουργία νήματος • Δημιουργία με pthread_create() • intpthread_create(pthread_t * thread, pthread_attr_t * attr, void* (*start_routine)(void *), void * arg); • π.χ. pthread_create(&tid, &attr, thread_fn, arg) • Αναμονή για τερματισμό (pthread_exit()) με pthread_join()
H pthread_join intpthread_join( pthread_tth, void **thread_return ); th- thread suspended until the thread identified by th terminates, either by calling pthread_exit() or by being cancelled. thread_return- If thread_return is not NULL, the return value of th is stored in the location pointed to by thread_return. When you want the caller to wait until a specific thread terminates, supply that thread's ID as the first argument. If you are interested in the exit code of the defunct thread, supply the address of an area to receive it. Αν δεν χρησιμοποιήσουμε την join, τι μπορεί να συμβεί; Hpthread_detach()είναι μια εναλλακτική της pthread_join()
Παράδειγμα: creating threads //******************************************************** // This is a sample threaded program in C. //The main thread creates // 4 threads. Each thread simply prints out a message // before exiting. Notice that Ive set the thread //attributes to joinable. // Compilation: gccthreads.c -lpthread //******************************************************** #include <stdio.h> #include <pthread.h> #define NUM_THREADS 4 void *thread_function( void *arg ) { int id; id = *((int *)arg); printf( "Hello from thread %d!\n", id ); pthread_exit( NULL ); } int main( void ) { inti, tmp; intarg[NUM_THREADS] = {0,1,2,3}; pthread_t thread[NUM_THREADS]; pthread_attr_tattr; // initialize and set the thread attributes pthread_attr_init( &attr ); pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_JOINABLE ); // creating threads for ( i=0; i<NUM_THREADS; i++ ) { tmp = pthread_create( &thread[i], &attr, thread_function, (void *)&arg[i] ); if ( tmp != 0 ) { fprintf(stderr,"Creating thread %d failed!",i); return 1; } } // joining threads for ( i=0; i<NUM_THREADS; i++ ) { tmp = pthread_join( thread[i], NULL ); if ( tmp != 0 ) { fprintf(stderr,"Joing thread %d failed!",i); return 1; } } return 0; } http://netcins.ceid.upatras.gr/OpSys-I/project/threads/thread_create.c
Παράδειγμα: joining threads #include <pthread.h> #include <stdio.h> #define NUM_THREADS 3 void *BusyWork(void *null) { inti; double result=0.0; for (i=0; i<1000000; i++) { result = result + (double)random(); } printf("result = %e\n",result); pthread_exit((void *) 0); } int main (intargc, char *argv[]) { pthread_t thread[NUM_THREADS]; pthread_attr_tattr; intrc, t; void *status; /* Initialize and set thread detached attribute */ pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); for(t=0; t<NUM_THREADS; t++) { printf("Creating thread %d\n", t); rc = pthread_create(&thread[t], &attr, BusyWork, NULL); if (rc) { printf("ERROR; return code from pthread_create() is %d\n", rc); exit(-1); } } /* Free attribute and wait for the other threads */ pthread_attr_destroy(&attr); for(t=0; t<NUM_THREADS; t++) { rc = pthread_join(thread[t], &status); if (rc) { printf("ERROR;return code from pthread_join() is %d\n", rc); exit(-1); } printf("Completed join with thread %d status= %ld\n",t, (long)status); } pthread_exit(NULL); } Output: Creating thread 0 Creating thread 1 Creating thread 2 Thread result = 1.073937e+15 Thread result = 1.073861e+15 Thread result = 1.073767e+15 Completed join with thread 0 status= 0 Completed join with thread 1 status= 0 Completed join with thread 2 status= 0 http://netcins.ceid.upatras.gr/OpSys-I/project/threads/thread_join.c
Αμοιβαίος αποκλεισμός • Τί γίνεται όταν θέλουμε να μεταβάλουμε τις μεταβλητές; • Πρέπει να εξασφαλίσουμε αποκλειστική πρόσβαση • Αμοιβαίος Αποκλεισμός • Η βιβλιοθήκη pthreads υλοποιεί μηχανισμούς με το όνομα mutex • Προσφέρουν έναν απλό τρόπο για να συγχρονίσουμε τα νήματα • μπορούμε να ‘προστατέψουμε’ τις κοινές μεταβλητές επιτρέποντας μόνο σε 1 νήμα να έχει πρόσβαση ανά πάσα χρονική στιγμή • Αναγκαστικά δημιουργούμε σημεία συμφόρησης του κώδικα • Πρέπει να είναι όσο το δυνατόν λιγότερες γραμμές κώδικα (το Κρίσιμο Τμήμα)
Condition Παράδειγμα int main (intargc, char *argv[]) { inti, rc; pthread_t threads[3]; pthread_attr_tattr; /* Initialize mutex and condition variable objects */ pthread_mutex_init(&count_mutex, NULL); pthread_cond_init (&count_threshold_cv, NULL); /* For portability, explicitly create threads in a joinable state */ pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); pthread_create(&threads[0], &attr, inc_count, (void *)&thread_ids[0]); pthread_create(&threads[1], &attr, inc_count, (void *)&thread_ids[1]); pthread_create(&threads[2], &attr, watch_count, (void *)&thread_ids[2]); /* Wait for all threads to complete */ for (i=0; i<NUM_THREADS; i++) { pthread_join(threads[i], NULL); } printf ("Main(): Waited on %d threads. Done.\n", NUM_THREADS); /* Clean up and exit */ pthread_attr_destroy(&attr); pthread_mutex_destroy(&count_mutex); pthread_cond_destroy(&count_threshold_cv); pthread_exit(NULL); } Starting watch_count(): thread 2 inc_count(): thread 0, count = 1, unlocking mutex inc_count(): thread 0, count = 2, unlocking mutex inc_count(): thread 0, count = 3, unlocking mutex inc_count(): thread 0, count = 4, unlocking mutex inc_count(): thread 0, count = 5, unlocking mutex inc_count(): thread 0, count = 6, unlocking mutex inc_count(): thread 0, count = 7, unlocking mutex inc_count(): thread 0, count = 8, unlocking mutex inc_count(): thread 0, count = 9, unlocking mutex inc_count(): thread 0, count = 10, unlocking mutex inc_count(): thread 1, count = 11, unlocking mutex inc_count(): thread 1, count = 12 Threshold reached. inc_count(): thread 1, count = 12, unlocking mutex inc_count(): thread 1, count = 13, unlocking mutex inc_count(): thread 1, count = 14, unlocking mutex inc_count(): thread 1, count = 15, unlocking mutex inc_count(): thread 1, count = 16, unlocking mutex inc_count(): thread 1, count = 17, unlocking mutex inc_count(): thread 1, count = 18, unlocking mutex inc_count(): thread 1, count = 19, unlocking mutex inc_count(): thread 1, count = 20, unlocking mutex watch_count(): thread 2 Condition signal received. Main(): Waited on 3 threads. Done.
Παράδειγμα timed_waitσε condition • Αντί για sleep, χρησιμοποιούμε το pthread_cond_timedwait http://netcins.ceid.upatras.gr/OpSys-I/project/threads/thread_timed_wait.c
Παραδείγματα • http://netcins.ceid.upatras.gr/OpSys-I/project/POSIXThreads.htm • http://netcins.ceid.upatras.gr/OpSys-I/project/threads