Teoria współbieżności - Laboratorium

Programowanie współbieżne - wątki 1


Wątki

Cztery typy programowania wielowątkowego:

  1. Niezależne wątki. Najprostszy model: wątki niepowiązane ze sobą. Mechanizmy programistyczne: podstawowe abstrakcje do tworzenia wątków.
  2. Powiązane, niesynchronizowane wątki. Wątki powiązane ze sobą, jednak nie oddziałują na siebie i nie posiadają danych współdzielonych. Np. problem podzielony na podproblemy, z których każdy przetwarzany jest przez oddzielny wątek. Mechanizmy programistyczne: pule wątków.
  3. Wątki wzajemnie wykluczające się. Wątki operują na współdzielonych danych i muszą być synchronizowane. Np. wątki czytające i modyfikujące stan zmiennej. Mechanizmy programistyczne: synchronizacja wątków (semafory, blokady etc.)
  4. Komunikujące się, wzajemnie wykluczające wątki. Wątki operują na współdzielonych danych, ale również komunikują się / koordynują działania. Np. zależność w stylu producent-konsument. Mechanizmy programistyczne: koordynacja typu wait/notify, zmienne warunkowe.

Wątki w języku Java

  1. Wbudowane w język
  2. Dwa rodzaje implementacji
    • Przez dziedziczenie z klasy Thread

      Klasa:

      class MyThread extends Thread {
           . . .
           public void run() {
                . . .
           }
      }
      
      Tworzenie obiektu i uruchamianie wątku:
      MyThread t = new MyThread();
      t.start();
      
    • Przez implementację interfejsu Runnable

      Klasa:

      class MyThreadR implements Runnable {
           . . .
           public void run() { 
                . . . 
           } 
      }
      
      Tworzenie i uruchamianie:
      MyThreadR r = new MyThreadR();
      Thread t = new Thread(r);
      t.start();
      
  3. Metoda run()
    public void run() { 
    // kod wątku
    }
    
  4. Klasa Thread

  5. Niektore wazne metody
    void setName(String name)
    String getName()
    void setPriority(int newPriority)
    int getPriority()
    void join()
    static void sleep(long milis, int nanos)
    public static Thread currentThread()
    String toString()
    

Wątki w JVM

Wyścig

  1. Zjawisko wyścigu (race condition) występuje gdy wątki współbieżnie korzystają z zasobu dzielonego (np. zmiennej), przy czym przynajmniej jeden z nich zmienia stan tego zasobu.
  2. Wyścig często jest przyczyną niedeterministycznego zachowania się programu i może prowadzić do trudnych do wykrycia błędów.
  3. Pojęcie thread-safety (bezpieczeństwo dla wątków, wielobieżność): kod jest bezpieczny dla wątków, gdy jego współbieżne wykonanie nie powoduje sytuacji wyścigu.

Zadanie 1

Zaimplementować program, w którym działają dwa wątki posiadające dostęp do wspólnego obiektu Counter, na którym można wykonać dwie operacje: inc i dec (zwiększenie/zmniejszenie stanu o 1, stan początkowy = 0). Jeden wątek cały czas inkrementuje licznik, drugi dekrementuje, oba robią to w pętli 1e9 razy. Na końcu (po zakończeniu działania obu wątków) program wypisuje końcowy stan licznika.

Zadanie 2

W systemie dziala N wątkow, które dzielą obiekt licznika (początkowy stan licznika = 0). Każdy wątek wykonuje w pętli 5 razy inkrementację licznika. Zakładamy, że inkrementacja składa się z sekwencji trzech instrukcji: read, inc, write (odczyt z pamięci, zwiększenie o 1, zapis do pamięci). Wątki nie są synchronizowane.
  • Jaka jest teoretycznie najmniejsza wartość licznika po zakończeniu działania wszystkich wątków i jaka kolejność instrukcji (przeplot) do niej prowadzi?
  • Analogiczne pytanie -- jaka jest maksymalna wartość licznika i odpowiedni przeplot instrukcji?

Bibliografia

  1. JVM architecture explained


Bartosz Baliś, balis at agh.edu.pl