pptx

advertisement
NIKOΛΑΟΣ ΝΤΙΡΛΗΣ
5ο ΦΡΟΝΤΙΣΤΗΡΙΟ
ΑΙΘΟΥΣΑ Β4
1


Ένα thread έχει: ID, program counter,
register set, stack
Μοιράζεται με τα άλλα threads της ίδιας
διεργασίας τον κώδικα, τα δεδομένα και
τους άλλους πόρους που του έχουν
διατεθεί από το ΛΣ (σήματα, αρχεία κτλ)
Πλεονεκτήματα των νημάτων σε σχέση με τις
διεργασίες:


Όταν μια process είναι blocked, τίποτα δεν
τρέχει. Όταν ένα thread είναι blocked, τα άλλα
threads της ίδιας process εκτελούνται.
Δημιουργία και τερματισμός threads είναι
πολύ πιο οικονομικός από τις αντίστοιχες
ενέργειες πάνω σε processes. Αυτό συμβαίνει
κυρίως γιατί τα threads μιας διεργασίας
μοιράζονται το ίδιο address space.

Switch time ανάμεσα σε δύο threads είναι πολύ πιο
μικρός

Communication time πολύ πιο μικρός.

Αξιοποίηση δυνατοτήτων σύγχρονων αρχιτεκτονικών
(πχ Intel Hyper-Threading processors)
POSIX Threads library: pthread.h μας δίνει
δυνατότητες να:




Δημιουργούμε και καταστρέφουμε threads
Passing messages and data between threads
Scheduling thread execution
Saving and restoring thread contexts
Η 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
-7
-


Αρχικά η συνάρτηση main δημιουργεί το
κεντρικό νήμα
Όλα τα υπόλοιπα νήματα πρέπει να
δημιουργηθούν κατά την εκτέλεση
-8
-


Αντίστοιχη της fork() για το process
Η συνάρτηση pthread_create έχει τις
ακόλουθες παραμέτρους
1. Ταυτότητα (αριθμός) νήματος – τιμή που
επιστρέφει η συνάρτηση
2. Παράμετροι νήματος – attributes, NULL για
προκαθορισμένες παραμέτρους
3. Συνάρτηση εκκίνησης – η συνάρτηση που θα
εκτελεστεί μόλις δημιουργηθεί το νέο νήμα
4. Παράμετροι συνάρτησης – οι μεταβλητές που θα
περαστούν στην συνάρτηση μόλις εκτελεστεί
-9
-
int pthread_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()
◦ int pthread_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()
11
-
int pthread_join(
pthread_t th,
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, τι μπορεί να συμβεί;
H pthread_detach() είναι μια εναλλακτική της pthread_join()
//********************************************************
// 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: gcc threads.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 )
{
int i, tmp;
int arg[NUM_THREADS] = {0,1,2,3};
pthread_t thread[NUM_THREADS];
pthread_attr_t attr;
}
// 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
13
-
#include <pthread.h>
#include <stdio.h>
#define NUM_THREADS 3
void *BusyWork(void *null) {
int i; 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 (int argc, char *argv[]) {
pthread_t thread[NUM_THREADS];
pthread_attr_t attr; int rc, 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
14
-






Τί γίνεται όταν θέλουμε να μεταβάλουμε τις
μεταβλητές;
Πρέπει να εξασφαλίσουμε αποκλειστική
πρόσβαση
Αμοιβαίος Αποκλεισμός
Η βιβλιοθήκη pthreads υλοποιεί μηχανισμούς με το
όνομα mutex
Προσφέρουν έναν απλό τρόπο για να
συγχρονίσουμε τα νήματα
μπορούμε να ‘προστατέψουμε’ τις κοινές
μεταβλητές επιτρέποντας μόνο σε 1 νήμα να έχει
πρόσβαση ανά πάσα χρονική στιγμή
◦ Αναγκαστικά δημιουργούμε σημεία συμφόρησης του
κώδικα
◦ Πρέπει να είναι όσο το δυνατόν λιγότερες γραμμές
κώδικα (το Κρίσιμο Τμήμα)
15
-
int main (int argc, char *argv[])
{
int i, rc;
pthread_t threads[3];
pthread_attr_t attr;
/* 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);
}
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.
/* Clean up and exit */
pthread_attr_destroy(&attr);
pthread_mutex_destroy(&count_mutex);
pthread_cond_destroy(&count_threshold_cv);
pthread_exit(NULL);
16
-

Αντί για sleep, χρησιμοποιούμε το
pthread_cond_timedwait
http://netcins.ceid.upatras.gr/OpSys-I/project/threads/thread_timed_wait.c
17
-


http://netcins.ceid.upatras.gr/OpSys-I/project/POSIXThreads.htm
http://netcins.ceid.upatras.gr/OpSys-I/project/threads
18
-
Download