/******************************************************************************/ /** @file "Pthreads/C/Primer 7 - monitor/crate.c" @brief Prikaz upotrebe kreirane strukture za opis monitora. Berači donose po nekoliko punih gajbica do puta na ivici njive. Kada pored puta berači sakupe barem VAN_CAPACITY gajbica, treba da probude jedan od procesa Traktora, da dodju do puta kraj njive i pokupe onoliko gajbica koliki je kapacitet prikolice. Za realizaciju koristi monitor (pthread_monitor_t). Procesi traktori pozivaju funkciju ready_pick dok berači pozivaju funkciju leave_crate.@n @n @author Miloš Gligorić @author Andrija Bosnjaković */ /******************************************************************************/ #include #include "mps.h" /******************************************************************************/ /** @def NUM_OF_PICKERS @brief Broj berača u sistemu. */ #define NUM_OF_PICKERS 5 /** @def NUM_OF_TRACTOR @brief Broj traktora u sistemu. */ #define NUM_OF_TRACTOR 2 /** @def VAN_CAPACITY @brief Kapacitet prikolice (u gajbicama). */ #define VAN_CAPACITY 200 /******************************************************************************/ /** @var monitor @brief Monitor nad kojim će se vršiti pozivi funkcija */ pthread_monitor_t monitor; /** @brief Funkcija monitora koju će pozivati procesi Beraci @param monitor Monitor nad kojim se poziva funkcija @param args Argumenti funkcije @param data Podaci monitora Proces Berač poziva ovu funkciju kada donese gajbice pored puta. Svaki Berač zna koliko gajbica može da ponese. Kako je u pitanju monitorska procedura nema potrebe za dodatnom sinhronizacijom. Ukoliko je nakon ostavljanja gajbica broj jedank ili veći kapacitetu prikolice poziva se jedan proces Traktor. */ void leave_crate(pthread_monitor_t *monitor, void *args, void *data) { int *num_of_crate_nexttoroad = (int*) data; int my_crate_num = (int) args; // ostavljanje gajbica pored puta *num_of_crate_nexttoroad += my_crate_num; printf("berac %d doneo gajbice ; pored puta %d\n", my_crate_num, *num_of_crate_nexttoroad); // ukoliko je broj jednak kapacitetu potrebno je pozvati Traktor if (*num_of_crate_nexttoroad >= VAN_CAPACITY) pthread_monitor_broadcast(monitor); } /** @brief Funkcija monitora koju će pozivati procesi Traktori @param monitor Monitor nad kojim se poziva funkcija @param args Argumenti funkcije @param data Podaci monitora Proces Traktor poziva ovu funkciju kada je spreman da pretera gajbice. Traktor dolazi po gajbice tak nakon sto ga je jedan do procesa čeraca pozvao (javio da ima dovoljno gajbica pored puta). */ void ready_pick(pthread_monitor_t *monitor, void *args, void *data) { int *num_of_crate_nexttoroad = (int*) data; // ceka da mu neko od beraca javi da ima dovoljno gajbica while (*num_of_crate_nexttoroad < VAN_CAPACITY) pthread_monitor_wait(monitor); // odvozi gajbice printf("traktor %d tera gajbice\n", (int)args); *num_of_crate_nexttoroad -= VAN_CAPACITY; } /******************************************************************************/ /** @brief Opis beskorisnog posla */ void idle() { int i, j; for (i = 0; i < 100000; i++) for (j = 0; j < 1000; j++); } /** @brief Posao za niti Berače. @param idb Generički pokazivač na broj niti @return Vraća rezultat izvršavanja funkcije pthread_exit Nit ide sledećim tokom. Najpre prolazi neko vreme u branju a kada je to završeno nit poziva funkciju monitora preko koje javlja da je odredjeni broj gajbica donela pored puta. Nit donosti id*2 broj gajbica +1. */ void* Picker(void *idb) { int id = (int) idb; printf("berac: %d\n", id); while (1) { // bere idle(); // ostavlja gajbice pored puta pthread_monitor_sync(&monitor, leave_crate, (void*)(id*2)); } pthread_exit(NULL); } /** @brief Posao za niti Traktor @param idt Generički pokazivač na broj niti @return Vraća rezultat izvršavanja funkcije pthread_exit Traktori čekaju da ih neko od procesa berača pozove. Ovo ostvaruju pozivom fukcije ready_pick monitora. Nakon toga voze neko vreme. */ void* Tractor(void *idt) { printf("traktor: %d\n", (int)idt); while(1) { // spreman da pokupi gajbice pthread_monitor_sync(&monitor, ready_pick, idt); // odvozi gajbice idle(); } pthread_exit(NULL); } /** @brief Glavna nit programa. @param argc Broj argumenata komandne linije. @param argv Argumenti komandne linije. @return Vrača status izvršenja programa. */ int main(int argc, char *argv[]) { int i; void *status; pthread_attr_t attr; pthread_t pickers[NUM_OF_PICKERS]; pthread_t tractors[NUM_OF_TRACTOR]; int num_of_crate_nexttoroad = 0; #ifdef WIN32 pthread_win32_process_attach_np(); #endif // svaka nit bice kreirana kao joinable pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); // inicijalizacija monitora pthread_monitor_init(&monitor, &num_of_crate_nexttoroad); // kreiranje niti beraca for (i = 0; i < NUM_OF_PICKERS; i++) { pthread_create(&pickers[i], &attr, Picker,(void*)i); } // kreiranje niti traktora for (i = 0; i < NUM_OF_TRACTOR; i++) { pthread_create(&tractors[i], &attr, Tractor, (void*)i); } // oslobadjanje resura pthread_attr_destroy(&attr); // cekanje svih niti na zavrsetak for (i = 0; i < NUM_OF_PICKERS; i++) { pthread_join(pickers[i], &status); } for (i = 0; i < NUM_OF_TRACTOR; i++) { pthread_join(tractors[i], &status); } // oslobadjanje resursa pthread_monitor_destroy(&monitor); pthread_exit(NULL); #ifdef WIN32 pthread_win32_process_detach_np(); #endif }