Języki i Techniki Programowania II Wykład 7 Współbieżność 1
Programy, Procesy, Wątki Program to zestaw instrukcji do wykonania, dane do przetworzenia, mechanizmy sterujące (stos) Proces w komputerze to instancja programu z własnymi danymi i mechanizmami sterującymi Wątek (thread, lightweight process, kernel-space thread) różni się od procesu tym że współdzieli dane Czasem mówi się o włóknach (fiber, user-space thread, green thread) dla wątków w przestrzeni zasobów użytkownika
Sposoby realizacji współbieżności Timesharing: Cooperative multitasking (green threads) - proces kończy działanie gdy: zakończy działanie zablokuje się na operacji blokującej np. I/O dopuści procesy inne do pracy (yield) Wielozadaniowość z wywłaszczaniem (Pre-emptive multitasking) proces może zostać wstrzymany przez scheduler systemy operacyjnego
Problemy w przetwarzaniu współbieżnym while(flag!=1) { //!!! flag=0 //instrukcje wymagajace oddzielenia...... flag=1
Istotne pojęcia Sekcja Krytyczna Zestaw danych wymagających wyłącznej obsługi ze strony 1 procesu/wątku Semafor (Edsger Dijkstra THE Operating System) zmienna strażnik - operacja test&set Monitor klasa mogąca być wykonana przez kilka procesów, chroniona mechanizmem wzajemnego wykluczania (Mutex), obejmująca jakąś sekcję krytyczną
Poprawność Programu Współbieżnego Dwa type własności poprawności: Bezpieczeństwo (safety) Problemy: niepoprawność (race conditions) Żywotność (liveness) Problemy globalne: zakleszczenie (deadlock, livelock) Problemy lokalne: wykluczenie (lockout), zagłodzenie (starvation)
Klasyczne zagadnienia Problem Śpiącego Golibrody 3 monitory: golibrody, kolejki klientów, mutex Problem 5-ciu filozofów zagłodzenie zakleszczenie Rozwiązanie: wprowadzenie porządku dla monitorów
Klasa Thread java.lang.thread metoda public void run() zawiera zadania do wykonania uruchamiamy nowy wątek poprzez public void start() a NIE poprzez run()
Klasa Thread public class SimpleThread extends Thread { public SimpleThread(String str) { super(str); public void run() { for (int i = 0; i < 10; i++) { System.out.println(i + " " + getname()); try { sleep((long)(math.random() * 1000)); catch (InterruptedException e) { System.out.println("DONE! " + getname());
Klasa Thread public class TwoThreadsTest { public static void main (String[] args) { new SimpleThread("Jamaica").start(); new SimpleThread("Fiji").start();
Klasa Thread
Interfejs Runnable public interface Runnable { public void run (); Stosujemy gdy nie chcemy stracić hierarchii klas: przy implementacji appletów, własnych mechanizmów etc. etc.
Cykl Życia Wątku
Scheduling Dany wątek przerywa działanie gdy: Przechodzi w stan Non Runnable Wątek o wyższym priorytecie się obudził wykonał yield() (trafia wtedy na kolejkę FIFO wątków o tym samym priorytecie) Zakończył metodę run()
Mutex Obsługa mutexa: modyfikator metody synchronized blok synchronized(obj) {...
Mutex class SynchStack { int sp = 0; int data[] = new int[6]; public synchronized void push(int i) { data[sp]=i; sp++; public synchronized int pop() { sp--; return data[sp];
Mutex class SynchStack { int sp = 0; int data[] = new int[6]; public void push(int i) { synchronized(this) { data[sp]=i; sp++; public int pop() { synchronized(this) { sp--; return data[sp];
Mutex Komunikacja między wątkami odbywa się przy użyciu dwu kolejek związanych w wątkami: Kolejka synchronized dostęp do monitora związanego z daną instancją Kolejka wait / notify pozwalająca na sprawdzanie szczególnych warunków związanych z daną instancją wait(), wait(long) należy posiadać monitor by je wywołać, monitor natychmiast jest zwalniany notify(), notifyall() - należy posiadać monitor by je wywołać
Mutex class SynchStack { int sp = 0; int data[] = new int[6]; public synchronized void push(int i) { while(sp>=6) { try { this.wait(); catch(interruptedexception e) {... data[sp]=i; sp++; this.notifyall();
Mutex public synchronized int pop() { while(sp<=0) { try { this.wait(); catch(interruptedexception e) {... sp--; this.notifyall(); return data[sp]; //POPRAWNE, NADAL MAMY MONITOR
Synchronizacja public class Producer extends Thread { private CubbyHole cubbyhole; private int number; public Producer(CubbyHole c, int number) { cubbyhole = c; this.number = number;
Synchronizacja public void run() { for (int i = 0; i < 10; i++) { cubbyhole.put(number, i); try { sleep((int)(math.random() * 100)); catch (InterruptedException e) {
Synchronizacja public class Consumer extends Thread { private CubbyHole cubbyhole; private int number; public Consumer(CubbyHole c, int number) { cubbyhole = c; this.number = number; public void run() { int value = 0; for (int i = 0; i < 10; i++) value = cubbyhole.get(number);
Synchronizacja public class CubbyHole { private int contents; private boolean available = false; public synchronized int get(int who) { while (available == false) { try { wait(); catch (InterruptedException e) { available = false; System.out.println("Consumer " + who + " got: " + contents); notifyall();return contents;
Synchronizacja public synchronized void put(int who, int value) { while (available == true) { try { wait(); catch (InterruptedException e) { contents = value; available = true; System.out.println("Producer " + who + " put: " + contents); notifyall();
Synchronizacja public class ProducerConsumerTest { public static void main(string[] args) { CubbyHole c = new CubbyHole(); Producer p1 = new Producer(c, 1); Consumer c1 = new Consumer(c, 1); p1.start(); c1.start();
Synchronizacja Producer #1 put: 0 Consumer #1 got: 0 Producer #1 put: 1 Consumer #1 got: 1 Producer #1 put: 2 Consumer #1 got: 2 Producer #1 put: 3 Consumer #1 got: 3 Producer #1 put: 4 Consumer #1 got: 4 Producer #1 put: 5...
Pipes public static Reader process(reader source) throws IOException { BufferedReader in = new BufferedReader(source); PipedWriter pipeout = new PipedWriter(); PipedReader pipein = new PipedReader(pipeOut); PrintWriter out = new PrintWriter(pipeOut); new ProcessThread(out, in).start(); return pipein;
Pipes public class ProcessThread extends Thread { private PrintWriter out = null; private BufferedReader in = null; public ProcessThread(PrintWriter out, BufferedReader in) { this.out = out; this.in = in;
Pipes public void run() { if (out!= null && in!= null) { try { String input; while ((input = in.readline())!= null) { out.println(process(input));//blocking I/O out.flush(); out.close(); catch (IOException e) { System.err.println("ProcessThread run: " + e);
Pipes private String process(string source) { String processedstring=null;... return processedstring;