Autor sekcije: Vedran Miletić

Python: dodatne usluge operacijskog sustava: višenitnost

Why did the multithreaded chicken cross the road?

to To other side. get the

Pojam procesne niti

  • POSIX Threads, poznati i pod nazivom Pthreads, su POSIX standard za implementaciju procesnih niti
    • omogućavaju procesima paralelizam izvođenja zasnovan na procesnim nitima i dijeljenoj memoriji
    • Linux koristi Native POSIX Thread Library (NPTL)
    • dokumentacija je dostupna putem man phtreads, man pthread.h i man pthread_*
  • module threading (službena dokumentacija) nudi pristup POSIX threads sučelju
  • threading.Thread(target=funkcija, args=(arg1, arg2))
    • t.start() započinje izvođenje procesne niti
    • t.is_alive() vraća True ako se procesna nit i dalje izvodi
    • t.join() čeka da procesna nit da završi s izvođenjem (“pridružuje” joj se; donekle slično os.wait())
    • t.run() nije isto što i t.start(); pokreće funkciju koja je dana kao target unutar trenutne procesne niti, ne stvara novu procesnu nit
    • t.name
  • threading.enumerate() vraća listu svih trenutno aktivnih niti

Zadatak

  • Definirajte funkciju countdown_to_zero(n) koja prima kao argument prirodni broj n i radi odbrojavanje, odnosno u while petlji smanjue broj za 1 sve dok ne dođe do nule.
  • Pokrenite tri niti t1, t2, t3 redom za brojeve 651929250, 421858921, 2188312. Pripazite da i ovdje (arg1,) nije isto što i (arg1).
  • U glavnom procesu “odspavajte” 5 sekundi, a zatim provjerite jesu li živi t1, t2 i t3, i one koji jesu pridružite na glavni proces.

Rad sa zaključavanjem i semaforima

  • race condition – kod zapisivanja vrijednosti dijeljene varijable od strane više procesa istovremeno može doći do problema
  • threading.Lock()
    • lock.acquire([blocking])
    • lock.release()
  • threading.RLock()
    • rlock.acquire([blocking])
    • rlock.release()

Zadatak

Napišite program koji računa zbroj prvih 500000 prirodnih brojeva u dvije procesne niti; definirajte globalnu varijablu zbroj, i učinite jedna procesna nit u globalnu varijablu zbraja brojeve od 1 do 250000, a druga od 250001 do 500000.

Izvedite program bez zaključavanja, s običnim zaključavanjem i s višestrukim zaključavanjem. Ima li ovdje potrebe za višestrukim zaključavanjem? Objasnite zašto.

Zadatak

Analizirajte vrijeme potrebno za izvođenje programa za sljedeće varijante.

  • Promijenite program iz prethodnog zadatka da računa produkt brojeva u danom rasponu umjesto zbroja. Usporedite vrijeme izvođenja tog programa i programa iz prethodnog zadatka.
  • Pored toga, usporedite performanse kod varijante koja dohvaća lock u svakoj iteraciji for petlje s vremenom izvođenja varijante koja to dohvaća lock prije for petlje. Koja je brža? Objasnite zašto. (Raspon smanjite po potrebi.)
  • Naposlijetku, isprobajte korištenje višestrukog zaključavanja umjesto običnog. Ima li razlike u vremenu izvođenja? Objasnite zašto.
  • threading.Condition([lock])
    • cv.acquire()
    • cv.release()
    • cv.notify([n])
    • cv.notify_all()
    • cv.wait([timeout])

Todo

Ovdje nedostaje objašnjenje i zadatak.

  • threading.Semaphore([value])
    • s.acquire([blocking])
    • s.release()
  • threading.BoundedSemaphore([value])
    • bs.acquire([blocking])
    • bs.release()

Zadatak

Knjižnica nudi tri knjige:

  • Marko Marulić: Judita, 5 komada
  • Fjodor Mihajlovič Dostojevski: Zločin i kazna, 3 komada
  • Albert Camus: Stranac, 4 komada

Reprezentirajte te tri knjige u programu kao tri niza znakova proizvoljnog sadržaja, i pridružite im semafore s odgovarajućom vrijednosti. Hoćete li koristiti ograničene semafore? Objasnite zašto.

Napišite funkciju lektira() koja prima jedan argument tipa znakovni niz, a to je ime učenika, koje se zatim ispisuje na ekran (npr. "Ja sam Domagoj i došao sam u knjižnicu"). Učenik zatim “posuđuje te tri knjige”, odnosno dohvaća njihove semafore i radi na njima acquire(), pa “čita te knjige i šara na margini”, odnosno prvo ispisuje znakovne nizove na ekran, a zatim dopisuje na kraj proizvoljan sadržaj. Naposlijetku “vraća te tri knjige”, odnosno radi release().

Učinite da “7 učenika dolazi u knjižnicu”, odnosno pokrenite 7 procesnih niti za učenike imena redom Domagoj, Ivan, Luka, Snežana, Romana, Sonja, Marta.

  • threading.Timer(interval, funkcija) pokreće funkciju u posebnoj procesnoj niti nakon što prođe vremenski interval trajanja danog u sekundama
    • t.start()
    • t.cancel()

Zadatak

Kuhate čaj i treba vam 1 minuta da zavrije voda, a istovremeno u pećnici koja ima pokvaren timer pečete kolačiće madelaine koji će biti taman kako treba za 2 minute. Napravite program sa dva timera, svaki sa pripadnom funkcijom, od kojih će jedna ispisati na ekran "Voda spremna za čaj!", a druga "Kolačići madelaine taman kako treba!" u odgovarajućim trenucima.

  • threading.Barrier([parties])
    • e.wait()
    • e.reset()
    • e.abort()

Zadatak

Dodajte dijeljenu barijeru u obje funkcije prethodnog zadatka tako da se po završetku izrade čaja, odnosno kolačića, čeka na onu drugu stranu, a zatim na ekran ispiše:

“I čim sam prepoznao okus u lipov čaj namočena komada madelaine, koji mi je svake nedjelje davala tetka Leonie (tada još doduše nisam znao razlog, zbog koga me ta uspomena tako usrećivala, nego sam to otkriće morao odgoditi za mnogo poslije), odmah se pojavi i stara, siva kuća na ulicu, u kojoj je bila njena soba, pa se kao pozorišni dekor pridruži malom paviljonu, koji je gledao na vrt, a koji su na njenoj stražnjoj strani nadogradili za moje roditelje (i baš to je bio onaj krnji komad, koji sam do sad jedini vidio); a s kućom se pojavi i grad. Trg, kamo su me slali prije ručka, ulice, kojima sam trčao od jutra do večeri, po svakom vremenu, i šetnje, na koje smo odlazili, kad je bilo lijepo vrijeme. I kao što se dešava u onoj igri, kojom se Japanci zabavljaju uranjajući u porculansku zdjelu punu vode komadiće do tad bezlična papira, koji se tek što je umočen, isteže, savija, bojadiše, diferencira, pretvara u cvijeće, kuće i određene osobe, koje je moguće prepoznati, tako je i sad sve cvijeće iz našeg vrta, iz Swannova perivoja, tako su svi lopoči s Vivonne, oni dobri seoski ljudi, njihovi mali domovi, crkva i cio Combray sa svojom okolinom, tako je sve što ima oblik i čvrstoću, i grad i vrtovi, izašlo iz moje čaše čaja.”

Dodatni zadatak

Napišite program koji vrši zbroj kvadrata brojeva u rasponu od 1 do 500000 u 3 niti (raspodijelite po želji). Iskoristite višenitnosti i varijablu u koju ćete spremiti zbroj učinite dijeljenom; iskoristite zaključavanje kod promjene varijable u svakoj od niti; napravite dijeljenu barijeru između tri niti tako da niti čekaju jedna na drugu i istovremeno završavaju izvođenje.

  • threading.Event()
    • e.is_set()
    • e.set()
    • e.clear()
    • e.wait([timeout])

Zadatak

Pečete Ledo Croissante koji zahtijevaju 15 minuta za odmrzavanje i 20 minuta u pećnici. Napravite dvije procesne niti, od kojih jedna pokreće funkciju odmrzavanje(n), gdje n broj minuta koje se kroasani odmrzavaju, i drugu koja pokreće funkciju pecnica(n), gdje je n broj minuta koje se kroasani peku u pećnici. Pokrenite istovremeno obje niti, ali učinite da druga nit čeka na događaj odmrzavanja kroasana koji prva nit postavlja.

Dodatni zadatak

Napišite program koji vrši zbroj kubova brojeva u rasponu od 1 do 300000 u 3 niti i raspodijelite tako da 1. nit računa raspon od 1 do 100000, 2. nit od 100001 do 200000, 3. nit od 200001 do 300000. Iskoristite višenitnosti i varijablu u koju ćete spremiti zbroj učinite dijeljenom; iskoristite zaključavanje kod promjene varijable u svakoj od niti; napravite događaj koji postavlja 3. nit u trenutku kad završi s izvođenjem, i učinite da na njega čekaju preostale dvije niti.