AtomCaml: First-Class Atomicity via Rollback

Transkrypt

AtomCaml: First-Class Atomicity via Rollback
AtomCaml: First-Class Atomicity via
Rollback
●
●
Autorzy: Michael F. Ringenburg i Dan
Grossman
Opracował Maciej Ciurlik na potrzeby
przedmiotu Metody Bezpiecznego
Programowania
1
Plan wykładu
●
Dlaczego stosować atomowość
●
Cechy AtomCaml
●
atomic i yield_r
●
Wywoływanie funkcji języka C
●
Decyzje projektowe
●
Implementacja AtomCaml
●
Wydajność
2
Dlaczego stosować atomowość?
„Writing
code
in
which
threads
communicate via mutable shared memory
will never be easy, but there is an
increasing belief that locks and condition
variables (the most common concurrency
primitives in today’s high-level languages)
make matters worse.”
3
Dlaczego stosować atomowość?
●
●
●
Warunki wyścigu często występują w
nowoczesnym oprogramowaniu
W rozbudowanym oprogramowaniu
poprawne stosowanie zamków jest trudne
Odnalezienie fragmentów kodu
powodujących błędy synchronizacji
nie jest proste
4
Dlaczego stosować atomowość?
●
●
●
Atomowe bloki kodu wykonają się bez
przeplatania dostępu do pamięci (no
interleaving), nawet jeśli kod jest kiepsko
napisany.
Fair scheduling pilnuje aby wątki nie
zostały zagłodzone
Programiści często uzyskują atomowość
poprawnie stosując istniejące
mechanizmy synchronizujące (Cormac
Flanagan and Shaz Qadeer. Types for atomicity.)
5
Zastosowanie atomowości
●
Systemy operacyjne
●
Relacyjne bazy danych
●
Systemy rozproszone
●
Rosnące zainteresowanie wśród twórców
języków programowania
6
Cechy AtomicCaml
●
●
●
●
Mocniejsze gwarancje niż w przypadku
implementacji dla Javy (Harris)
Unikanie wyrafinowanych struktur danych
oraz protokołów zatwierdzenia STM na
rzecz prostego mechanizmu „loggingand-rollback”
API pozwalające wywołać natywny kod z
bloku atomowego
Wsteczna kompatybilność z Ocaml
7
Wyrażenie atomic
●
●
●
Funkcja typu (unit­>’a)­>’a
Pobiera blok kodu jako argument i
wykonuje go atomowo
Implementacja zapewnia brak
przeplatania w dostępie do pamięci
8
Wyrażenie atomic
let totalWidgets = atomic (fun () ­>
!blackWidgets let totalWidgets + !blueWidgets = !blackWidgets in
+ !blueWidgets in
if totalWidgets >0 if totalWidgets > 0
then print_string (pickWidget () ^ " available")
then print_string (pickWidget () ^ " available")
else raise NoWidgets
else raise NoWidgets)
9
Wyrażenie atomic
●
●
●
Gdy wątek natrafi na kod w bloku
atomowym zaczyna go wykonywać
Jeśli wątek nie został wywłaszczony
oznacza to, że kod wykonał się atomowo
(kod nie jest wykonywany równolegle)
Jeśli wątek zostanie wywłaszczony
podczas wykonywania bloku atomowego
zmiany dokonane przez ten kod są
wycofywane, kod wykonywany jest
ponownie przy kolejnym wywołaniu wątka
10
Wyrażenie atomic
●
●
●
Blok atomic może zawierać:
–
Dowolny kod języka Ocaml włączając
wywołania funkcji
–
Wywołania zewnętrznych funkcji napisanych
wC
Kod atomowy morze rzucać wyjątki, które
mogą zostać obsłużone wewnątrz lub na
zewnątrz bloku atomic
Zagnieżdżanie wyrażenie atomic jest
nadmiarowe.
11
Wyrażenie yield_r
●
●
●
Zapis do bufora:
–
Sprawdź czy bufor jest pełny, jeśli nie to
zapisz
–
Jeśli tak to czekaj
Co jeśli bufor zostanie wypełniony po
sprawdzeniu miejsca a przed naszym
zapisem?
Identyczny problem istnieje kiedy
programujemy używając atomic
12
Wyrażenie yield_r
●
●
●
Należy sprawdzić dostępność bufora
wewnątrz tego samego bloku
Jeśli bufor jest pełny kończymy
wykonywanie bloku i ponawiamy zapis
gdy pojawi się miejsce w buforze
Czy wystarczy użyć yield ?
13
Wyrażenie yield_r
yield
Re-schedule the calling thread without
suspending it. This function can be used
to give scheduling hints, telling the
scheduler that now is a good time to
switch to other threads.
14
Wyrażenie yield_r
„We noticed that the yielding code is often
waiting for a mutable reference to have
its contents changed and it is useless to
rerun the thread until such change occur.”
15
Wyrażenie yield_r
●
●
„We noticed that the yielding code is
often waiting for a mutable reference to
have its contents changed and it is
useless to rerun the thread until such
change occur.”
yield_r x suspends the thread and
allows (but does not require) the
scheduler to skip the suspended thread
whenever the contents of the reference
bound to x are the same as when
16
yield_r was called
Wyrażenie yield_r
let add_to_bbuf bbuf item =
Thread.atomic (fun () →
if (is_full_bbuf bbuf) then
Thread.yield_r bbuf.out_ptr
else ();
bbuf.buffer.(!(bbuf.in_ptr))<­item;
advance bbuf bbuf.in_ptr)
let remove_from_bbuf bbuf =
Thread.atomic (fun () →
if (is_empty_bbuf bbuf) then
Thread.yield_r bbuf.in_ptr
else ();
let ans = bbuf.buffer.(!(bbuf.out_ptr)) in
advance bbuf bbuf.out_ptr;
17
ans)
Wywoływanie funkcji języka C
●
●
Jeśli kod może być uruchomiony atomowo
bez żadnych modyfikacji:
external foo : type_of_foo = "c_foo"
Jeśli napisano osobną wersje funkcji
bezpieczną do ładowania z sekcji
atomowej:
external foo : type_of_foo = "c_foo1 c_foo2"
Wywołanie foo w bloku nie atomowym
uruchomi c_foo1. Wywołanie foo w bloku
atomowym uruchomi c_foo2
18
Wywoływanie funkcji języka C
●
Jeśli funkcja nigdy nie ma być
wywoływana atomowo:
external foo : type = "c_foo1 raise_on_atomic"
jeśli foo zostanie wywołane wewnątrz
atomowego bloku to zostanie rzucony
wyjątek wskazujący nazwę źle wywołanej
funkcji
19
Przygotowanie atomowych wersji
funkcji języka C
●
●
caml_register_rollback_action(void(
*reg_func)(void*), void* reg_env)
Funkcja powoduje wywołanie reg_func z
argumentem reg_env gdy wykonywany
blok atomowy zostanie wycofany
caml_register_commit_action(void (*reg_func)(void*), void* reg_env
Funkcja powoduje wywołanie reg_func z
argumentem reg_env gdy wykonywany
blok atomowy zostanie zakończony
20
Decyzje projektowe
●
Czy zezwolić na operacje wejścia w
blokach atomowych?
21
Decyzje projektowe
●
Czy zezwolić na operacje wejścia w
blokach atomowych?
–
Każda funkcja wejścia wywoływana w bloku
atomowym czyta kolejne wartości w buforze
22
Decyzje projektowe
●
Czy zezwolić na operacje wejścia w
blokach atomowych?
–
Każda funkcja wejścia wywoływana w bloku
atomowym czyta kolejne wartości w buforze
–
W przypadku wycofania przeczytane wartości
zostają z powrotem wpisane do bufora
23
Decyzje projektowe
●
Czy zezwolić na operacje wejścia w
blokach atomowych?
–
Każda funkcja wejścia wywoływana w bloku
atomowym czyta kolejne wartości w buforze
–
W przypadku wycofania przeczytane wartości
zostają z powrotem wpisane do bufora
Konieczność sprawdzenia przez wszystkie
funkcje wejścia (nawet nie atomowe) czy
bufor nie jest zajęty przez inne
wycofywane wątki.
24
Decyzje projektowe
●
Czy zezwolić na operacje wejścia w
blokach atomowych?
–
Każda funkcja wejścia wywoływana w bloku
atomowym czyta kolejne wartości w buforze
–
W przypadku wycofania przeczytane wartości
zostają z powrotem wpisane do bufora
Brak możliwości ograniczenia wielkości
bufora ze względu na niemożność
przewidzenia ilości danych do wycofania
25
Decyzje projektowe
●
●
Bufor operacji wyjścia dla funkcji
atomowych nie może zostać ograniczony
bo nie wolno go opróżnić do momentu
zakończenia wykonywania bloku
atomowego
Bufor operacji wyjścia dla funkcji nie
atomowych może zostać opróżniony w
dowolnym momencie
26
Decyzje projektowe
●
Co zrobić gdy wyjątek rzucony w bloku
atomowym nie zostanie obsłużony
wewnątrz tego bloku?
27
Decyzje projektowe
●
Co zrobić gdy wyjątek rzucony w bloku
atomowym nie zostanie obsłużony
wewnątrz tego bloku?
–
Zakończyć wykonywanie bloku?
–
Wycofać dokonane zmiany?
28
Decyzje projektowe
Co zrobić gdy wyjątek rzucony w bloku
atomowym nie zostanie obsłużony
wewnątrz tego bloku?
let x = ref 0
atomic (fun () →
x := 1;
f() (* f may raise an exception *))
if !x = 0 then failwith "huh" else ...
29
Implementacja AtomCaml
●
W przypadku wycofania bloku żadne
dowody częściowego wykonania kodu nie
mogą być widoczne
30
Implementacja AtomCaml
●
W przypadku wycofania bloku żadne
dowody częściowego wykonania kodu nie
mogą być widoczne
–
Odczyty nie są logowane
–
System loguje wszystkie wykonane zapisy
oraz poprzednie wartości
–
Zmiany lokalne wewnątrz bloku atomowego
nie są logowane
31
Implementacja AtomCaml
32
Implementacja AtomCaml
●
Jak upewnić się, że atomowy blok
zostanie w końcu wykonany i
sprawiedliwie zarządzać zasobami
33
Implementacja AtomCaml
●
Jak upewnić się, że atomowy blok
zostanie w końcu wykonany i
sprawiedliwie zarządzać zasobami
–
Scheduler przyznaje więcej czasu po 2x
nieudanych próbach wykonania kodu
–
Scheduler pomija wątki przez kilka rund
proporcjonalnie do ilości dodatkowego czasu
–
Scheduler może nadać wyższy priorytet
innym wątkom.
34
Implementacja AtomCaml
●
Jak logować zmiany dokonane przez
zewnętrzne funkcje wywołane z bloku
atomowego nie spowalniając tych samych
funkcji wywołanych nie atomowo?
35
Implementacja AtomCaml
●
Jak logować zmiany dokonane przez
zewnętrzne funkcje wywołane z bloku
atomowego nie spowalniając tych samych
funkcji wywołanych nie atomowo?
–
Kompilator generuje dwie wersje funkcji
„logującą” dla kodu atomowego oraz
„zwykłą” dla pozostałego kodu
36
Wydajność
●
Wpływ na wydajność?
37
Wydajność
38
Koniec
●
Dziękuje za uwagę
●
Pytania?
39

Podobne dokumenty