/* Primjer programa koji bi trebao prikazati protokol nasljedjivanja prioriteta ako ga sustav podrzava ! */ #include #include #include #include /* na Linuxu: radi moguce (vece?) POSIX kompatibilnosti (emulacije) korisiti */ #define __USE_UNIX98 #include /* ako ne prevodi i javlja cudne greske (stariji sustavi), komentirati prevodjenje: # gcc -lpthread -lrt nas_prio.c (opcionalno ukljucit i optimizaciju, npr. -03) pokretanje (mora se kao root, inace nece se moci postaviti RT rasporedjivanje): # ./a.out (ili sudo ./a.out) (sustav moze postat 'cudan', obzirom da se ovo vrti prije sveg ostaloga!) Na pinusu prevoditi sa dodatnom zastavicom: -D_POSIX_PTHREAD_SEMANTICS Iako, na pinusu nece raditi (treba biti root)! */ #define BROJAC 10000000000000ULL //puno ! //makro za poziv funkcije i provjeru povratne vrijednosti: //ako povratna vrijednost nije nula ispisi gresku i stani #define PF(FUN, ...) \ ({ \ int pv = FUN(__VA_ARGS__); \ if (pv != 0) { \ fprintf(stderr, "Greska: %s (%d)\n", #FUN, __LINE__); \ exit(1); \ } \ pv; \ }) //npr. poziv: a = neka_funkcija(p1, p2, p3); //treba zapisati kao: a = PF(neka_funkcija, p1, p2, p3); //broj iteracija za 1 s volatile static unsigned long long brojac = BROJAC; volatile static unsigned int kraj = 0; //simulira rad - trosenje procesorskog vremena static void broji(int v, char ime, char dio) { unsigned long long k = 0; int j; for (j = 1; j <= v && !kraj; j++) { printf("Dretva %c :: dio %c (%d/%d)\n", ime, dio, j, v); for (k = 0; k < brojac && !kraj; k++) asm volatile ("":::"memory"); //nista korisno, ali da i nakon optimizacije ipak //ostane petlja } if (kraj) { /* mjerim */ brojac = k; printf("1 s = %lld iter\n", brojac); kraj = 0; } } //za mjerenje koliko iteracija treba za jednu sekundu //dosta neprecizno, ali za ovaj primjer zadovoljavajuce static void alarm_f (union sigval a) { kraj = 1; return; } struct pd { int a_dio, b_dio, c_dio, d_dio; //trajanje pojedinih elemenata u sek. pthread_mutex_t *mon_az, *mon_bz, *mon_cz, *mon_dz; pthread_mutex_t *mon_ao, *mon_bo, *mon_co, *mon_do; int pocetna_odgoda; int prio; char ime; }; //simuliranje obavljanje "dijela" posla static void dio (int trajanje, pthread_mutex_t *monz, pthread_mutex_t *mono, char ime, char dio) { if (monz != NULL) pthread_mutex_lock(monz); broji(trajanje, ime, dio); if (mono != NULL) pthread_mutex_unlock(mono); } //pridjela brojeva dretvama (nije zasticeno, ali...) static int id_dretve() { static id = 1; return id++; } static void *dretva(void *param) { struct pd *p = param; int id = id_dretve(); struct timespec koliko; PF(pthread_setschedprio, pthread_self(), p->prio); //moze se i komentirati, jer je vec i prije stvaranja postavljen koliko.tv_nsec = 0; koliko.tv_sec = p->pocetna_odgoda; nanosleep(&koliko, NULL); printf("Dretva %c pocela (id=%d, prio=%d)\n", p->ime, id, p->prio); dio(p->a_dio, p->mon_az, p->mon_ao, p->ime, 'A'); dio(p->b_dio, p->mon_bz, p->mon_bo, p->ime, 'B'); dio(p->c_dio, p->mon_cz, p->mon_co, p->ime, 'C'); dio(p->d_dio, p->mon_dz, p->mon_do, p->ime, 'D'); return NULL; } int main() { struct sigevent dog; dog.sigev_notify = SIGEV_THREAD; dog.sigev_signo = 0; dog.sigev_value.sival_int = 0; dog.sigev_notify_function = alarm_f; dog.sigev_notify_attributes = NULL; timer_t timerid; //stvaranje alarma, ali nije automatski i "pokrenut" PF(timer_create, CLOCK_REALTIME, &dog, &timerid); struct itimerspec koliko; koliko.it_value.tv_sec = 1; koliko.it_value.tv_nsec = 0; koliko.it_interval.tv_sec = 0; koliko.it_interval.tv_nsec = 0; //postavi vrijeme aktivacije i pokreni prethodni alarm PF(timer_settime, timerid, 0, &koliko, NULL); //dok alarm ne istekne "vrti" petlju - gledaj koliko iteracija treba broji(1, 'G', 'A'); //obrisi alarm PF(timer_delete, timerid); int min = sched_get_priority_min(SCHED_FIFO); int max = sched_get_priority_max(SCHED_FIFO); //printf("Prioriteti za SCHED_FIFO su u rangu: %d - %d\n", min, max); int pocetni = (min + max) / 2; struct sched_param prio; //postavi nacin rasporedjivanja i prioritet za pocetnu dretvu (zapravo //za proces) prio.sched_priority = pocetni; PF(sched_setscheduler, getpid(), SCHED_FIFO, &prio); //inicijaliziraj atribute za monitor pthread_mutexattr_t mutex_attr; PF(pthread_mutexattr_init, &mutex_attr); PF(pthread_mutexattr_settype, &mutex_attr, PTHREAD_MUTEX_RECURSIVE); PF(pthread_mutexattr_setprotocol, &mutex_attr, PTHREAD_PRIO_INHERIT); //inicijaliziraj monitor pthread_mutex_t mon1, mon2; PF(pthread_mutex_init, &mon1, &mutex_attr); PF(pthread_mutex_init, &mon2, &mutex_attr); //definiraj parametre za zadatke/dretve struct pd params[5] = { { 3,9,0,3, NULL, &mon1, NULL, NULL, NULL, &mon1, NULL, NULL, 0, pocetni - 5, 'A' }, { 3,0,0,3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 6, pocetni - 4, 'B' }, { 3,3,3,3, NULL, &mon2, &mon1, NULL, NULL, NULL, &mon2, &mon1, 9, pocetni - 3, 'C' }, { 3,0,0,3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 18, pocetni - 2, 'D' }, { 3,3,0,3, NULL, &mon2, NULL, NULL, NULL, &mon2, NULL, NULL, 21, pocetni - 1, 'E' } }; //definiraj svojstva za dretve (nacin rasporedjivanja) pthread_attr_t thread_attr; PF(pthread_attr_init, &thread_attr); PF(pthread_attr_setschedpolicy, &thread_attr, SCHED_FIFO); int i; pthread_t dr[5]; for (i = 0; i < 5; i++) { struct sched_param prio; prio.sched_priority = params[i].prio; PF(pthread_attr_setschedparam, &thread_attr, &prio); //stvarenje nove dretve PF(pthread_create, &dr[i], &thread_attr, dretva, ¶ms[i]); } //cekaj da sve stvorene dretve zavrse s radom for (i = 0; i < 5; i++) PF(pthread_join, dr[i], NULL); //obrisi mutexe (nije neophodno ako nisu u zajednickoj memoriji) PF(pthread_mutex_destroy, &mon1); PF(pthread_mutex_destroy, &mon2); return 0; }