Predavanje 09 Odjel za matematiku 1 PARALELNO PROGRAMIRANJE POSIX threadovi za C++
Predavanje 09 Odjel za matematiku 2 Programske niti (thread) unutar procesa Danas ćemo se upoznati s POSIX thread bibliotekom za C/C++ Proces Thread ili nit predstavlja tok naredbi unutar procesa (programa). Proces može sadržavati više niti koje se izvršavaju paralelno Programske niti mogu dijeliti istu memoriju nit 1 nit 2 nit 3 Moderna računala višeprocesorska ili barem višejezgrena (multicore)
Predavanje 09 Odjel za matematiku 3 Paralelno programiranje Svoj program možete paralelizirati na način da stvorite više od jednog procesa ( fork ) u kojima se vaš program izvršava otežavajuće: svaki proces živi u svom adresnom prostoru (drugim riječima, dva procesa ne mogu pisati/brisati po istoj memorijskoj lokaciji) Komunikacija dva procesa (MPI) Stvaranje ( fork ) procesa košta više od stvaranja novoga threada sjajno: mogućnost stvaranja programa koji će se izvršavati na više različitih računala (distribuirano računanje) Ukoliko želi te paralelizirati program za jedno računalo, napravite to pomoću threadova
Predavanje 09 Odjel za matematiku 4 POSIX thread - pthread pthread biblioteka nam omogućuje jednostavno stvaranje višenitnog programa Prirodno je namjenjena za UNIX-like računala: FreeBSD, NetBSD, GNU/Linux, Mac OS X and Solaris Postoji implementacija i za Windowse IDEJA: stvoriti tzv. funkciju thread - funkcija koja je ujedno i thread Svaki thread sadrži svoj jedinstveni Thread ID Svaki thread vraća povratnu vrijednost tzv. errno (tipa integer) pthread vraća "0" ukoliko je sve prošlo OK. Osnovni thread iz kojega kreirate druge threadove zovemo Master Thread
Predavanje 09 Odjel za matematiku 5 Stvaranje threada ili niti pthread_create(): stvaranje threada int pthread_create(pthread_t * thread, const pthread_attr_t * attr, void * (*start_routine)(void *), void *arg); Argumenti: thread vraća thread ID (pthread_t je predefinirani unsigned long int) attr ukoliko postavljen na NULL, defaultne vrijednosti (najčešće) void * (*start_routine) pokazivač na thread funkciju *arg pokazivač na argument thread funkciji ukoliko više od jednog argumenta, enkapsulirajte ih unutar klase ili strukture pthread_join(): čekaj na završetak drugog threada int pthread_join(pthread_t th, void **thread_return); Argumenti: th ID threada na čiji završetak treba čekati thread_return vrijednost koju vraća funkcija thread (NULL)
Predavanje 09 Odjel za matematiku 6 pthread: Primjer 1 Naš zadatak je iz MainThreada stvoriti dva threada Svakom od dva threada treba proslijediti neku poruku koju threadovi trebaju ispisati na zaslon Npr. funkcija thread bi mogla izgledati ovako: void *thread_funkcija_ispisi_poruku( void * poruka ) char *message; message = (char *) ptr; cout << message << endl; Primjetite da thread funkcija vraća void * i prima void *. Zašto? Napravimo C++ implementaciju našeg primjera
Predavanje 09 Odjel za matematiku 7 pthread: Primjer 2 Zbrajanje vektora zbrojimo dva vektora paralelno C++ funkcija: void add( int *a, int *b, int *c ) int tid = 0; while (tid < N) c[tid] = a[tid] + b[tid]; tid += 1;
Predavanje 09 Odjel za matematiku 8 pthread: Primjer 2 Thread 1: Thread 2: void add( int *a, int *b, int *c, int start ) int tid = start; // start = 0 while (tid < N) c[tid] = a[tid] + b[tid]; tid += 2; void add( int *a, int *b, int *c, int start ) int tid = start; // start = 1 while (tid < N) c[tid] = a[tid] + b[tid]; tid += 2; Implementirajmo zbrajanje vektora u C++-u
Predavanje 09 Odjel za matematiku 9 pthread: Mutex Prisjetite se da threadovi djele adresni prostor Dobro: pojednostavnjuje komunikaciju izmedju threadova Loše: Lako napraviti grešku koja se teško otkriva Primjer: Dva threada koja pristupaju istoj varijabli brojac int brojac=0; void *povecajbrojac() brojac++; Ukoliko instanciramo dva threada povecajbrojac(), što mislite da će se desiti?
Predavanje 09 Odjel za matematiku 10 pthread: Mutex Želimo zaštititi pristup memorijskoj adresi brojača dok mu pristupa neki od threadova Mutex Mutual exclusion Ispravno implementirana funkcija povecajbrojac() pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER; int counter=0; void *povecajbrojac() pthread_mutex_lock( &mutex1 ); brojac++ ; pthread_mutex_unlock( &mutex1 ); Primijetite da je sada dijeljena memorijska lokacija brojac ispravno zaštićena