Systemy operacyjne - Współbieżność

1. Współbieżność to umiejętność wykonywania procesów w tym samym czasie. Mówimy o niej w kontekście: procesów, wątków i procesorów. Współbieżność może mieć miejsce w przypadku: 
  • kiedy wiele aplikacji działa w sposób jednoczesny (trzeba przemyśleć proces synchronizacji, ponieważ dwa lub więcej procesów korzystających z tej samej komórki pamięci może wywołać błędy)
  • aplikacji wielowątkowych (może wystąpić sytuacja tzw. deadlock - zakleszczenia; czyli momentu kiedy jeden proces czeka na drugi aż dokończy wykonywać swoje czynności, podczas kiedy żaden z nich nie wykonuje żadnych czynności)
  • systemu operacyjnego. 

2. Hazard ("race condition") - ostatni proces zapisujący do jakiejś zmiennej dzieloną pomiędzy wątkami determinuje wartość tej zmiennej.
3. Problemy występujące przy współbieżności:
  • wzajemne wykluczenie (sytuacja, gdy dwa lub więcej procesów wymaga dostępu do pojedynczego niepodzielnego krytycznego zasobu)
  • deadlock (wyżej wytłumaczone)
  • livelock (sytuacja podobna do deadlocku, z tym, że tutaj procesy nie zawieszają się, ciągle coś robią, jednak nie mają żadnego postępu podczas wykonywania programu).
  • zagłodzenie (więcej niż jeden proces chce wykorzystać dany zasób, ale dostęp do niego jest zsynchronizowany - proces na swoją kolej może czekać nieskończenie lub bardzo długo).
4. W trakcie programowania aplikacji współbieżnych musimy być w stanie zidentyfikowania krytycznych sekcji kodu - czyli takich linijek kodu, przy których wiele procesów korzystając z tego  programu powodowałyby błędy. Aby powiadomić o takiej sytuacji różne procesy, stosuje się wysłanie wiadomości do innych procesów o tym, że mają czekać lub mogą już wchodzić w krytyczną sekcję kodu. W przeciwnym przypadku mielibyśmy sytuację typu deadlock lub zagłodzenie.

5. Wzajemne wykluczenie musi być realizowane przez mechanizm, który wymusza to wzajemne wykluczenie (proces nie może tego zignorować). Procesy mogą pozostawać w krytycznej sekcji kodu jedynie przez określony czas. Wymuszanie wzajemnego wykluczenia robi się poprzez:
  • podejście software (np. algorytm Dekkera, algorytm Petersona)
  • podejście hardware (dezaktywacja przerwań - jeśli proces uruchomi konkretne przerwanie to komputer przestaje reagować sprzętowo, na to konkretne przerwanie, dopóki proces nie skończy się procedura obsługi tego przerwania)
6. Wykorzystanie przerwań wzajemnego wykluczenia polega na zaimplementowaniu instrukcji atomowej (operacja, w której proces sprawdza czy zasób jest wolny i ewentualnie oznacza jako zasób zajęty, musi być niepodzielna).

7. Synchronizacja procesów i zapewnienie wzajemnego wykluczenia:
  • stosowanie monitorów (konstrukcje używane w niektórych środowiskach np. Javie - synchronized - system automatycznie monitorował wywołanie tej konkretnej metody, która posiada krytyczne sekcje kodu ) 
  • stosowanie semaforów (są oparte na pewnej zmiennej całkowitej ile zasobów się znajduje; jeśli ta zmienna całkowita ma wartość jest niezerową to znaczy, że proces sprawdzający ile jest zasobu wie, że może z tego zasobu skorzystać, jeśli nie - to znaczy, że musi zaczekać; semafory implementują 3 operacje: inicjalizacja zmiennej całkowitej, operacja dekrementująca wartość semafora, operacja inkrementująca wartość semafora)
  • wysyłanie wiadomości (nie jest skuteczną metodą; wymaga implementacji funkcji send() oraz receive(), wymaga implementacji całego protokołu komunikacyjnego; wymaga określenia stuktury tej wiadomości)